JavaScript Credit Card Validation

I was reading 2600 on the bus recently and came across a credit generation algorithms which got me thinking… if you are building a web application that charges credit cards, at which point would card validation make most sense? I came to the conclusion that an efficient system, would check the credit card number was valid on the client side. This way there is little-to-no network traffic containing invalid card numbers.

Checking credit card numbers is actually pretty simple. Most services will use something called a Luhn Check, which multiplies odd indices by two, sums their digits and then divides the total sum by ten. If the result of the sum % 10 == 0 then the card number is ‘likely’ to be valid.

I came up with a a short function to validate credit card numbers passed as Strings or Floats.

  var cardValid = function( cardNo ){    
    var sum = 0, iNum;
    for( var i in cardNo+='' ){
      iNum = parseInt(cardNo[i]);
      sum += i%2?iNum:iNum>4?iNum*2%10+1:iNum*2;
    return !(sum%10);

To use this function, just call cardValid( cardNo ) which will return either true or false.


We moved off of Disqus for data privacy and consent concerns, and are currently searching for a new commenting tool.

  1. I’m not a javascript programmer, would it be possible for you to post an example of how this script might display an error message when the onBlur event occurs on the \”CardNumber\” field and the number in that field is not a valid credit card number?

  2. Nice work! I know this is old but I was just implementing it was doing some test and found that the credit card number 123 come out as valid. That’s because the result is 1*2 + 2 + 3*2 = 10. and 10%10 = 0, returning the function as true.

    Obviously, a bit more checks must be done to lessen the traffic of invalid creditcard numbers.

  3. The validation in the above script does not work for Amex cards (and perhaps other cards with an odd number of digits).\u00a0 A Luhn check starts at the rightmost digit and moves left.\u00a0 This means that the final digit in the card is always added into the sum without doubling.\u00a0 This script works from left to right, exposing the last digit of a 15-character number (as AMEX uses) to the doubling operation.\u00a0 This results in an incorrect sum and failure for AMEX cards.\u00a0 While not nearly as efficient and elegant as the solution originally proposed, this seems to work for all cards that I know of.

    function luhn (ccnumber) {
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 /* Luhn check */
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var cc_sum = 0;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var parsedCC;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var cclen = ccnumber.length;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for (i=cclen-1; i>=0; i–) {
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var charati = ccnumber[i] + ”;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 parsedCC = parseInt(charati);
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var oddeven = cclen-1 – i;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cc_sum += (oddeven%2 == 0) ? parsedCC :
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (parsedCC > 4) ? parsedCC * 2 % 10 + 1 :
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 parsedCC * 2;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var checkvalid = ((cc_sum % 10) == 0) ? true : false;
    \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return checkvalid;

Contact Us

We'd love to hear from you. Get in touch!


P.O. Box 961436
Boston, MA 02196