The Luhn Algorithm Explained — How Credit Card Validation Works
Every time you enter a credit card number online, the website checks it with the Luhn algorithm before sending it to the payment processor. This simple checksum formula, invented in 1954, catches accidental typos instantly. Here is exactly how it works, step by step, with working code you can copy into your own projects.
History
Hans Peter Luhn was a German-born computer scientist at IBM who patented the algorithm in 1954 (US Patent 2,950,048). Originally designed to validate identification numbers on punch cards, it became the standard checksum for credit card numbers when the modern credit card system was developed in the 1960s.
The patent expired in 1977, making the algorithm freely available. Today it is described in ISO/IEC 7812-1 as the standard for validating Primary Account Numbers (PANs) on payment cards. Every Visa, Mastercard, American Express, and Discover card number you have ever used passes the Luhn check.
What the Algorithm Does
The Luhn algorithm verifies that a number has not been mistyped. It works by performing a specific transformation on every other digit, summing all the results, and checking if the total is evenly divisible by 10. If it is, the number is valid. If not, at least one digit was entered incorrectly.
The key insight is that the last digit of every valid number is a check digit — it is specifically chosen to make the total sum divisible by 10. When generating a credit card number, you calculate the first 15 digits and then compute the 16th digit to satisfy the Luhn check.
Step-by-Step Walkthrough
Let us validate the number 4539 1488 0343 6467 (a Visa-format number generated by our Fake Credit Card Generator).
Step 1: Write out the digits
| Position | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Digit | 4 | 5 | 3 | 9 | 1 | 4 | 8 | 8 | 0 | 3 | 4 | 3 | 6 | 4 | 6 | 7 |
Step 2: Double every second digit from the right
Starting from the rightmost digit (position 16) and moving left, double every second digit — that is, positions 15, 13, 11, 9, 7, 5, 3, 1 (counting from the right, these are positions 2, 4, 6, etc.).
| Position | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Original | 4 | 5 | 3 | 9 | 1 | 4 | 8 | 8 | 0 | 3 | 4 | 3 | 6 | 4 | 6 | 7 |
| Doubled | 8 | 5 | 6 | 9 | 2 | 4 | 16 | 8 | 0 | 3 | 8 | 3 | 12 | 4 | 12 | 7 |
Step 3: If a doubled value is greater than 9, subtract 9
This is equivalent to adding the two digits of the doubled number (e.g., 16 → 1 + 6 = 7, or simply 16 - 9 = 7).
| Position | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Result | 8 | 5 | 6 | 9 | 2 | 4 | 7 | 8 | 0 | 3 | 8 | 3 | 3 | 4 | 3 | 7 |
Step 4: Sum all digits
8 + 5 + 6 + 9 + 2 + 4 + 7 + 8 + 0 + 3 + 8 + 3 + 3 + 4 + 3 + 7 = 80
Step 5: Check if divisible by 10
80 % 10 = 0 — The remainder is 0, so the number is valid.
Why It Catches Common Errors
The Luhn algorithm is specifically designed to detect the two most common types of accidental errors:
- Single-digit errors — Changing any one digit will change the sum, making it no longer divisible by 10. The algorithm catches 100% of single-digit errors.
- Adjacent transposition errors — Swapping two consecutive digits (e.g., typing "54" instead of "45") is caught in most cases. The doubling step makes the two digit positions contribute differently to the sum, so swapping them changes the total. The only exception is the pair 0 and 9 — swapping 09 to 90 (or vice versa) produces the same Luhn sum.
JavaScript Implementation
/**
* Validate a number using the Luhn algorithm.
* @param {string} number - The number to validate (digits only).
* @returns {boolean} True if the number passes the Luhn check.
*/
function luhnValidate(number) {
const digits = number.replace(/\D/g, '');
if (digits.length === 0) return false;
let sum = 0;
let alternate = false;
for (let i = digits.length - 1; i >= 0; i--) {
let n = parseInt(digits[i], 10);
if (alternate) {
n *= 2;
if (n > 9) n -= 9;
}
sum += n;
alternate = !alternate;
}
return sum % 10 === 0;
}
// Usage
console.log(luhnValidate('4539148803436467')); // true
console.log(luhnValidate('4539148803436468')); // false (last digit changed)
Generating a Check Digit
/**
* Calculate the Luhn check digit for a partial number.
* @param {string} partial - The number without its check digit.
* @returns {number} The check digit (0-9).
*/
function luhnCheckDigit(partial) {
const digits = partial.replace(/\D/g, '');
let sum = 0;
let alternate = true; // start true because we're adding one more digit
for (let i = digits.length - 1; i >= 0; i--) {
let n = parseInt(digits[i], 10);
if (alternate) {
n *= 2;
if (n > 9) n -= 9;
}
sum += n;
alternate = !alternate;
}
return (10 - (sum % 10)) % 10;
}
// Generate a valid Visa number
const partial = '453914880343646'; // 15 digits
const checkDigit = luhnCheckDigit(partial);
console.log(partial + checkDigit); // "4539148803436467"
Python Implementation
def luhn_validate(number: str) -> bool:
"""Validate a number using the Luhn algorithm."""
digits = [int(d) for d in number if d.isdigit()]
if not digits:
return False
# Reverse, double every second digit
total = 0
for i, d in enumerate(reversed(digits)):
if i % 2 == 1:
d *= 2
if d > 9:
d -= 9
total += d
return total % 10 == 0
def luhn_check_digit(partial: str) -> int:
"""Calculate the Luhn check digit for a partial number."""
digits = [int(d) for d in partial if d.isdigit()]
total = 0
for i, d in enumerate(reversed(digits)):
if i % 2 == 0: # note: 0-indexed, different parity
d *= 2
if d > 9:
d -= 9
total += d
return (10 - (total % 10)) % 10
# Usage
print(luhn_validate("4539148803436467")) # True
print(luhn_validate("4539148803436468")) # False
print(luhn_check_digit("453914880343646")) # 7
Where Else Is Luhn Used?
The Luhn algorithm is not exclusive to credit cards. It validates several other types of identification numbers:
- IMEI numbers — The 15-digit International Mobile Equipment Identity number on every mobile phone uses a Luhn check digit as its last digit.
- Canadian Social Insurance Numbers (SIN) — The 9-digit SIN uses Luhn validation. This is one reason why SIN numbers starting with 9 are reserved for temporary residents.
- US National Provider Identifier (NPI) — Healthcare provider IDs use Luhn with a prefix of "80840" prepended before validation.
- Some European national IDs — Certain countries use Luhn checksums in their national identification number schemes.
- Loyalty and membership cards — Many retail loyalty programs use Luhn-validated card numbers to catch scanning errors at point of sale.
Limitations
The Luhn algorithm is a simple error-detection mechanism, not a security feature:
- It does not prevent fraud — Anyone can generate a Luhn-valid number. The algorithm only catches accidental typos, not deliberate fabrication.
- It does not verify the card exists — A Luhn-valid number tells you nothing about whether a real bank account is behind it.
- It misses some transpositions — Specifically, swapping 0 and 9 in adjacent positions produces the same checksum.
- It does not validate the issuer — Luhn does not check whether the BIN (Bank Identification Number, the first 6 digits) belongs to a real bank.
For developers: Use Luhn validation as a first-pass filter to catch typos before hitting your payment API. But always rely on your payment processor (Stripe, Braintree, Adyen) for actual card validation — they check BIN ranges, expiry, CVV, and account status.
Try It Yourself
Generate Luhn-valid credit card numbers for testing your payment form validation. All numbers pass the Luhn check but are not connected to any real bank account.
Frequently Asked Questions
The Luhn algorithm (also called the Luhn formula or modulus 10 algorithm) is a checksum formula invented by Hans Peter Luhn at IBM in 1954. It detects accidental errors in identification numbers such as credit card numbers, IMEI numbers, and some national ID numbers. It works by doubling every second digit from the right, summing all digits, and checking if the total is divisible by 10.
No. The Luhn algorithm catches all single-digit errors and most adjacent transposition errors (swapping two consecutive digits). However, it cannot detect all possible transpositions — specifically, it misses the swap of 09 and 90. It also cannot detect deliberate fraud or verify that a card number is connected to a real account.
No. Passing the Luhn check only means the number is formatted correctly and has a valid checksum. Many numbers pass the Luhn check without being linked to any real bank account. Fake credit card generators produce Luhn-valid numbers specifically for testing payment form validation without using real cards.
The Luhn algorithm is used to validate IMEI numbers on mobile devices, Canadian Social Insurance Numbers (SIN), some European national ID numbers, US National Provider Identifier (NPI) numbers for healthcare, and some loyalty card and membership numbers. The algorithm is the same — only the digit count and prefix rules change.