Skip to content
CardCheck

Take it with you

Copy the check

The whole Luhn check fits in about fifteen lines. Each version below does the same thing: strip spaces and dashes, require 12 to 19 digits, then double, fold and add.

export function passesLuhn(input: string): boolean {
  const digits = input.replace(/[\s-]/g, "");
  if (!/^\d{12,19}$/.test(digits)) return false;

  let sum = 0;
  for (let i = 0; i < digits.length; i++) {
    let d = Number(digits[digits.length - 1 - i]);
    if (i % 2 === 1) {
      d *= 2;
      if (d > 9) d -= 9;
    }
    sum += d;
  }
  return sum % 10 === 0;
}

Before you ship it

  • Run the same check on your server. Anything a browser does can be skipped by someone who is not using your page.
  • Do not log card numbers, even failed ones. If you can, avoid handling them at all and use your payment provider's hosted fields.
  • Do not reject a number only because its brand is unknown to you. New ranges appear, so let the payment provider decide.
  • Accept spaces and dashes when people paste a number, and format it for them as they type.