[{"data":1,"prerenderedAt":2263},["ShallowReactive",2],{"en-javascript-category-articles":3},[4,1506],{"id":5,"title":6,"articleCover":7,"articleCoverEmbed":8,"articleCoverEmbedUploadDate":8,"articleCoverHeight":9,"articleCoverWidth":10,"authorId":11,"body":12,"categoriesIds":1491,"description":1493,"enAlternateSlug":1494,"extension":1495,"meta":1496,"navigation":286,"path":1497,"ptBrAlternateSlug":1498,"publishedAt":1499,"seo":1500,"sitemap":1501,"stem":1503,"updatedAt":1502,"wordCount":1504,"__hash__":1505},"blogEn\u002Fen\u002Fblog\u002Fhow-to-validate-cpf-with-javascript.md","How to validate a CPF with JavaScript","\u002Fimages\u002Fen\u002Fblog\u002Fjavascript\u002Fhow-to-validate-cpf-with-javascript.webp",null,720,1280,"thiago-nunes-batista",{"type":13,"value":14,"toc":1468},"minimark",[15,19,27,32,35,45,48,51,56,59,70,73,79,82,88,91,97,100,106,109,115,122,126,129,135,138,144,147,153,156,162,165,171,178,183,186,190,197,200,762,765,889,901,904,927,933,940,950,954,957,1150,1153,1157,1161,1164,1205,1212,1219,1223,1226,1233,1260,1267,1270,1274,1277,1280,1314,1317,1321,1324,1327,1331,1335,1338,1345,1348,1352,1355,1369,1372,1375,1407,1411,1414,1417,1420,1424,1433,1436,1440,1443,1446,1450,1456,1464],[16,17,18],"p",{},"The CPF (Cadastro de Pessoas Físicas) is the Brazilian individual taxpayer number, and almost every Brazilian sign-up form asks for it. Validating it on the front-end helps avoid mistakes in sign-up, checkout and login forms. On the back-end, validation is a second barrier against mistyped data and basic fraud.",[16,20,21,22,26],{},"In this article, you will understand the CPF algorithm and implement a ",[23,24,25],"strong",{},"CPF validation"," function in plain JavaScript, with no external library.",[28,29,31],"h2",{"id":30},"what-the-check-digits-are","What the check digits are",[16,33,34],{},"A CPF has 11 digits:",[36,37,38,42],"ul",{},[39,40,41],"li",{},"The first 9 are the base of the document.",[39,43,44],{},"The last 2 are the check digits.",[16,46,47],{},"These two digits are calculated from the previous ones. The idea is to catch common typing errors, like swapping or dropping a number.",[16,49,50],{},"The math check, however, does not confirm that the CPF exists, belongs to a specific person or is in good standing with the Receita Federal (Brazil's federal revenue service). It only checks whether the digits follow the CPF algorithm.",[52,53,55],"h3",{"id":54},"first-check-digit","First check digit",[16,57,58],{},"Take the CPF without formatting:",[60,61,67],"pre",{"className":62,"code":64,"language":65,"meta":66},[63],"language-text","52998224725\n","text","",[68,69,64],"code",{"__ignoreMap":66},[16,71,72],{},"The first 9 digits are:",[60,74,77],{"className":75,"code":76,"language":65,"meta":66},[63],"5 2 9 9 8 2 2 4 7\n",[68,78,76],{"__ignoreMap":66},[16,80,81],{},"Multiply each number by the weights from 10 down to 2:",[60,83,86],{"className":84,"code":85,"language":65,"meta":66},[63],"5×10 + 2×9 + 9×8 + 9×7 + 8×6 + 2×5 + 2×4 + 4×3 + 7×2\n",[68,87,85],{"__ignoreMap":66},[16,89,90],{},"The result is:",[60,92,95],{"className":93,"code":94,"language":65,"meta":66},[63],"50 + 18 + 72 + 63 + 48 + 10 + 8 + 12 + 14 = 295\n",[68,96,94],{"__ignoreMap":66},[16,98,99],{},"Now calculate the remainder of the division by 11:",[60,101,104],{"className":102,"code":103,"language":65,"meta":66},[63],"295 % 11 = 9\n",[68,105,103],{"__ignoreMap":66},[16,107,108],{},"Since the remainder is greater than 1, we do:",[60,110,113],{"className":111,"code":112,"language":65,"meta":66},[63],"11 - 9 = 2\n",[68,114,112],{"__ignoreMap":66},[16,116,117,118,121],{},"So the first check digit is ",[68,119,120],{},"2",".",[52,123,125],{"id":124},"second-check-digit","Second check digit",[16,127,128],{},"Now use the first 10 digits, including the check digit you just calculated:",[60,130,133],{"className":131,"code":132,"language":65,"meta":66},[63],"5 2 9 9 8 2 2 4 7 2\n",[68,134,132],{"__ignoreMap":66},[16,136,137],{},"Apply the weights from 11 down to 2:",[60,139,142],{"className":140,"code":141,"language":65,"meta":66},[63],"5×11 + 2×10 + 9×9 + 9×8 + 8×7 + 2×6 + 2×5 + 4×4 + 7×3 + 2×2\n",[68,143,141],{"__ignoreMap":66},[16,145,146],{},"The sum is:",[60,148,151],{"className":149,"code":150,"language":65,"meta":66},[63],"55 + 20 + 81 + 72 + 56 + 12 + 10 + 16 + 21 + 4 = 347\n",[68,152,150],{"__ignoreMap":66},[16,154,155],{},"The remainder of the division by 11 is:",[60,157,160],{"className":158,"code":159,"language":65,"meta":66},[63],"347 % 11 = 6\n",[68,161,159],{"__ignoreMap":66},[16,163,164],{},"Since the remainder is greater than 1:",[60,166,169],{"className":167,"code":168,"language":65,"meta":66},[63],"11 - 6 = 5\n",[68,170,168],{"__ignoreMap":66},[16,172,173,174,177],{},"The second check digit is ",[68,175,176],{},"5",". So the full CPF is:",[60,179,181],{"className":180,"code":64,"language":65,"meta":66},[63],[68,182,64],{"__ignoreMap":66},[16,184,185],{},"That is the CPF algorithm: calculate the first digit, add it to the sequence and calculate the second.",[28,187,189],{"id":188},"implementation-in-plain-javascript","Implementation in plain JavaScript",[16,191,192,193,196],{},"The function needs to handle formatted input, like ",[68,194,195],{},"529.982.247-25",", and also a string of digits with no punctuation.",[16,198,199],{},"One possible implementation is this:",[60,201,205],{"className":202,"code":203,"language":204,"meta":66,"style":66},"language-javascript shiki shiki-themes dracula","function validateCPF(cpf) {\n  \u002F\u002F Make sure the input is treated as text\n  cpf = String(cpf).replace(\u002F\\D\u002Fg, \"\");\n\n  \u002F\u002F A valid CPF must have exactly 11 digits\n  if (cpf.length !== 11) {\n    return false;\n  }\n\n  \u002F\u002F Reject CPFs made of the same digit\n  if (\u002F^(\\d)\\1{10}$\u002F.test(cpf)) {\n    return false;\n  }\n\n  \u002F\u002F Calculate the first check digit\n  let sum = 0;\n\n  for (let i = 0; i \u003C 9; i++) {\n    sum += Number(cpf[i]) * (10 - i);\n  }\n\n  let remainder = sum % 11;\n  const firstDigit = remainder \u003C 2 ? 0 : 11 - remainder;\n\n  \u002F\u002F The calculated first digit must match the one provided\n  if (firstDigit !== Number(cpf[9])) {\n    return false;\n  }\n\n  \u002F\u002F Calculate the second check digit\n  sum = 0;\n\n  for (let i = 0; i \u003C 10; i++) {\n    sum += Number(cpf[i]) * (11 - i);\n  }\n\n  remainder = sum % 11;\n  const secondDigit = remainder \u003C 2 ? 0 : 11 - remainder;\n\n  \u002F\u002F The calculated second digit must also match the one provided\n  return secondDigit === Number(cpf[10]);\n}\n","javascript",[68,206,207,231,238,281,288,294,311,323,329,334,340,375,384,389,394,400,416,421,456,485,490,495,514,547,552,558,579,588,593,598,604,616,621,649,671,676,681,697,725,730,736,756],{"__ignoreMap":66},[208,209,212,216,220,224,228],"span",{"class":210,"line":211},"line",1,[208,213,215],{"class":214},"s0Tla","function",[208,217,219],{"class":218},"sAOxA"," validateCPF",[208,221,223],{"class":222},"sCdxs","(",[208,225,227],{"class":226},"sGEwX","cpf",[208,229,230],{"class":222},") {\n",[208,232,234],{"class":210,"line":233},2,[208,235,237],{"class":236},"shSDL","  \u002F\u002F Make sure the input is treated as text\n",[208,239,241,244,247,250,253,256,258,262,266,268,271,274,278],{"class":210,"line":240},3,[208,242,243],{"class":222},"  cpf ",[208,245,246],{"class":214},"=",[208,248,249],{"class":218}," String",[208,251,252],{"class":222},"(cpf).",[208,254,255],{"class":218},"replace",[208,257,223],{"class":222},[208,259,261],{"class":260},"s-doY","\u002F",[208,263,265],{"class":264},"sIQBb","\\D",[208,267,261],{"class":260},[208,269,270],{"class":214},"g",[208,272,273],{"class":222},", ",[208,275,277],{"class":276},"seVfx","\"\"",[208,279,280],{"class":222},");\n",[208,282,284],{"class":210,"line":283},4,[208,285,287],{"emptyLinePlaceholder":286},true,"\n",[208,289,291],{"class":210,"line":290},5,[208,292,293],{"class":236},"  \u002F\u002F A valid CPF must have exactly 11 digits\n",[208,295,297,300,303,306,309],{"class":210,"line":296},6,[208,298,299],{"class":214},"  if",[208,301,302],{"class":222}," (cpf.length ",[208,304,305],{"class":214},"!==",[208,307,308],{"class":264}," 11",[208,310,230],{"class":222},[208,312,314,317,320],{"class":210,"line":313},7,[208,315,316],{"class":214},"    return",[208,318,319],{"class":264}," false",[208,321,322],{"class":222},";\n",[208,324,326],{"class":210,"line":325},8,[208,327,328],{"class":222},"  }\n",[208,330,332],{"class":210,"line":331},9,[208,333,287],{"emptyLinePlaceholder":286},[208,335,337],{"class":210,"line":336},10,[208,338,339],{"class":236},"  \u002F\u002F Reject CPFs made of the same digit\n",[208,341,343,345,348,350,353,356,359,362,365,367,369,372],{"class":210,"line":342},11,[208,344,299],{"class":214},[208,346,347],{"class":222}," (",[208,349,261],{"class":260},[208,351,352],{"class":214},"^",[208,354,223],{"class":355},"smvxG",[208,357,358],{"class":264},"\\d",[208,360,361],{"class":355},")",[208,363,364],{"class":214},"\\1{10}$",[208,366,261],{"class":260},[208,368,121],{"class":222},[208,370,371],{"class":218},"test",[208,373,374],{"class":222},"(cpf)) {\n",[208,376,378,380,382],{"class":210,"line":377},12,[208,379,316],{"class":214},[208,381,319],{"class":264},[208,383,322],{"class":222},[208,385,387],{"class":210,"line":386},13,[208,388,328],{"class":222},[208,390,392],{"class":210,"line":391},14,[208,393,287],{"emptyLinePlaceholder":286},[208,395,397],{"class":210,"line":396},15,[208,398,399],{"class":236},"  \u002F\u002F Calculate the first check digit\n",[208,401,403,406,409,411,414],{"class":210,"line":402},16,[208,404,405],{"class":214},"  let",[208,407,408],{"class":222}," sum ",[208,410,246],{"class":214},[208,412,413],{"class":264}," 0",[208,415,322],{"class":222},[208,417,419],{"class":210,"line":418},17,[208,420,287],{"emptyLinePlaceholder":286},[208,422,424,427,429,432,435,437,439,442,445,448,451,454],{"class":210,"line":423},18,[208,425,426],{"class":214},"  for",[208,428,347],{"class":222},[208,430,431],{"class":214},"let",[208,433,434],{"class":222}," i ",[208,436,246],{"class":214},[208,438,413],{"class":264},[208,440,441],{"class":222},"; i ",[208,443,444],{"class":214},"\u003C",[208,446,447],{"class":264}," 9",[208,449,450],{"class":222},"; i",[208,452,453],{"class":214},"++",[208,455,230],{"class":222},[208,457,459,462,465,468,471,474,476,479,482],{"class":210,"line":458},19,[208,460,461],{"class":222},"    sum ",[208,463,464],{"class":214},"+=",[208,466,467],{"class":218}," Number",[208,469,470],{"class":222},"(cpf[i]) ",[208,472,473],{"class":214},"*",[208,475,347],{"class":222},[208,477,478],{"class":264},"10",[208,480,481],{"class":214}," -",[208,483,484],{"class":222}," i);\n",[208,486,488],{"class":210,"line":487},20,[208,489,328],{"class":222},[208,491,493],{"class":210,"line":492},21,[208,494,287],{"emptyLinePlaceholder":286},[208,496,498,500,503,505,507,510,512],{"class":210,"line":497},22,[208,499,405],{"class":214},[208,501,502],{"class":222}," remainder ",[208,504,246],{"class":214},[208,506,408],{"class":222},[208,508,509],{"class":214},"%",[208,511,308],{"class":264},[208,513,322],{"class":222},[208,515,517,520,523,525,527,529,532,535,537,540,542,544],{"class":210,"line":516},23,[208,518,519],{"class":214},"  const",[208,521,522],{"class":222}," firstDigit ",[208,524,246],{"class":214},[208,526,502],{"class":222},[208,528,444],{"class":214},[208,530,531],{"class":264}," 2",[208,533,534],{"class":214}," ?",[208,536,413],{"class":264},[208,538,539],{"class":214}," :",[208,541,308],{"class":264},[208,543,481],{"class":214},[208,545,546],{"class":222}," remainder;\n",[208,548,550],{"class":210,"line":549},24,[208,551,287],{"emptyLinePlaceholder":286},[208,553,555],{"class":210,"line":554},25,[208,556,557],{"class":236},"  \u002F\u002F The calculated first digit must match the one provided\n",[208,559,561,563,566,568,570,573,576],{"class":210,"line":560},26,[208,562,299],{"class":214},[208,564,565],{"class":222}," (firstDigit ",[208,567,305],{"class":214},[208,569,467],{"class":218},[208,571,572],{"class":222},"(cpf[",[208,574,575],{"class":264},"9",[208,577,578],{"class":222},"])) {\n",[208,580,582,584,586],{"class":210,"line":581},27,[208,583,316],{"class":214},[208,585,319],{"class":264},[208,587,322],{"class":222},[208,589,591],{"class":210,"line":590},28,[208,592,328],{"class":222},[208,594,596],{"class":210,"line":595},29,[208,597,287],{"emptyLinePlaceholder":286},[208,599,601],{"class":210,"line":600},30,[208,602,603],{"class":236},"  \u002F\u002F Calculate the second check digit\n",[208,605,607,610,612,614],{"class":210,"line":606},31,[208,608,609],{"class":222},"  sum ",[208,611,246],{"class":214},[208,613,413],{"class":264},[208,615,322],{"class":222},[208,617,619],{"class":210,"line":618},32,[208,620,287],{"emptyLinePlaceholder":286},[208,622,624,626,628,630,632,634,636,638,640,643,645,647],{"class":210,"line":623},33,[208,625,426],{"class":214},[208,627,347],{"class":222},[208,629,431],{"class":214},[208,631,434],{"class":222},[208,633,246],{"class":214},[208,635,413],{"class":264},[208,637,441],{"class":222},[208,639,444],{"class":214},[208,641,642],{"class":264}," 10",[208,644,450],{"class":222},[208,646,453],{"class":214},[208,648,230],{"class":222},[208,650,652,654,656,658,660,662,664,667,669],{"class":210,"line":651},34,[208,653,461],{"class":222},[208,655,464],{"class":214},[208,657,467],{"class":218},[208,659,470],{"class":222},[208,661,473],{"class":214},[208,663,347],{"class":222},[208,665,666],{"class":264},"11",[208,668,481],{"class":214},[208,670,484],{"class":222},[208,672,674],{"class":210,"line":673},35,[208,675,328],{"class":222},[208,677,679],{"class":210,"line":678},36,[208,680,287],{"emptyLinePlaceholder":286},[208,682,684,687,689,691,693,695],{"class":210,"line":683},37,[208,685,686],{"class":222},"  remainder ",[208,688,246],{"class":214},[208,690,408],{"class":222},[208,692,509],{"class":214},[208,694,308],{"class":264},[208,696,322],{"class":222},[208,698,700,702,705,707,709,711,713,715,717,719,721,723],{"class":210,"line":699},38,[208,701,519],{"class":214},[208,703,704],{"class":222}," secondDigit ",[208,706,246],{"class":214},[208,708,502],{"class":222},[208,710,444],{"class":214},[208,712,531],{"class":264},[208,714,534],{"class":214},[208,716,413],{"class":264},[208,718,539],{"class":214},[208,720,308],{"class":264},[208,722,481],{"class":214},[208,724,546],{"class":222},[208,726,728],{"class":210,"line":727},39,[208,729,287],{"emptyLinePlaceholder":286},[208,731,733],{"class":210,"line":732},40,[208,734,735],{"class":236},"  \u002F\u002F The calculated second digit must also match the one provided\n",[208,737,739,742,744,747,749,751,753],{"class":210,"line":738},41,[208,740,741],{"class":214},"  return",[208,743,704],{"class":222},[208,745,746],{"class":214},"===",[208,748,467],{"class":218},[208,750,572],{"class":222},[208,752,478],{"class":264},[208,754,755],{"class":222},"]);\n",[208,757,759],{"class":210,"line":758},42,[208,760,761],{"class":222},"}\n",[16,763,764],{},"Usage examples:",[60,766,768],{"className":202,"code":767,"language":204,"meta":66,"style":66},"console.log(validateCPF(\"529.982.247-25\"));\n\u002F\u002F true\n\nconsole.log(validateCPF(\"52998224725\"));\n\u002F\u002F true\n\nconsole.log(validateCPF(\"529.982.247-26\"));\n\u002F\u002F false\n\nconsole.log(validateCPF(\"111.111.111-11\"));\n\u002F\u002F false\n",[68,769,770,796,801,805,826,830,834,855,860,864,885],{"__ignoreMap":66},[208,771,772,775,778,780,783,785,788,791,793],{"class":210,"line":211},[208,773,774],{"class":222},"console.",[208,776,777],{"class":218},"log",[208,779,223],{"class":222},[208,781,782],{"class":218},"validateCPF",[208,784,223],{"class":222},[208,786,787],{"class":276},"\"",[208,789,195],{"class":790},"s-mGx",[208,792,787],{"class":276},[208,794,795],{"class":222},"));\n",[208,797,798],{"class":210,"line":233},[208,799,800],{"class":236},"\u002F\u002F true\n",[208,802,803],{"class":210,"line":240},[208,804,287],{"emptyLinePlaceholder":286},[208,806,807,809,811,813,815,817,819,822,824],{"class":210,"line":283},[208,808,774],{"class":222},[208,810,777],{"class":218},[208,812,223],{"class":222},[208,814,782],{"class":218},[208,816,223],{"class":222},[208,818,787],{"class":276},[208,820,821],{"class":790},"52998224725",[208,823,787],{"class":276},[208,825,795],{"class":222},[208,827,828],{"class":210,"line":290},[208,829,800],{"class":236},[208,831,832],{"class":210,"line":296},[208,833,287],{"emptyLinePlaceholder":286},[208,835,836,838,840,842,844,846,848,851,853],{"class":210,"line":313},[208,837,774],{"class":222},[208,839,777],{"class":218},[208,841,223],{"class":222},[208,843,782],{"class":218},[208,845,223],{"class":222},[208,847,787],{"class":276},[208,849,850],{"class":790},"529.982.247-26",[208,852,787],{"class":276},[208,854,795],{"class":222},[208,856,857],{"class":210,"line":325},[208,858,859],{"class":236},"\u002F\u002F false\n",[208,861,862],{"class":210,"line":331},[208,863,287],{"emptyLinePlaceholder":286},[208,865,866,868,870,872,874,876,878,881,883],{"class":210,"line":336},[208,867,774],{"class":222},[208,869,777],{"class":218},[208,871,223],{"class":222},[208,873,782],{"class":218},[208,875,223],{"class":222},[208,877,787],{"class":276},[208,879,880],{"class":790},"111.111.111-11",[208,882,787],{"class":276},[208,884,795],{"class":222},[208,886,887],{"class":210,"line":342},[208,888,859],{"class":236},[16,890,891,892,895,896,898,899,121],{},"The ",[68,893,894],{},"replace(\u002F\\D\u002Fg, '')"," call removes everything that is not a digit. That lets the function accept both ",[68,897,195],{}," and ",[68,900,821],{},[16,902,903],{},"This is the regular expression that catches repeated digits:",[60,905,907],{"className":202,"code":906,"language":204,"meta":66,"style":66},"\u002F^(\\d)\\1{10}$\u002F;\n",[68,908,909],{"__ignoreMap":66},[208,910,911,913,915,917,919,921,923,925],{"class":210,"line":211},[208,912,261],{"class":260},[208,914,352],{"class":214},[208,916,223],{"class":355},[208,918,358],{"class":264},[208,920,361],{"class":355},[208,922,364],{"class":214},[208,924,261],{"class":260},[208,926,322],{"class":222},[16,928,929,930,932],{},"It matches an 11-character sequence made of the same digit. That keeps values like ",[68,931,880],{}," from being accepted.",[16,934,935,936,939],{},"This detail tends to catch people who have already struggled with the problem: CPFs with all digits equal pass the math, but they must be rejected explicitly. If you implement only the calculation, your code will treat ",[68,937,938],{},"11111111111"," as valid.",[16,941,942,943,121],{},"If you want to test inputs quickly without building a form, use ",[944,945,949],"a",{"href":946,"rel":947},"https:\u002F\u002Fcodigoaoponto.com\u002Fen\u002Ftools\u002Fcpf-validator",[948],"nofollow","our free online CPF validator",[52,951,953],{"id":952},"validation-in-the-form","Validation in the form",[16,955,956],{},"You can call the function on the form's submit event:",[60,958,960],{"className":202,"code":959,"language":204,"meta":66,"style":66},"const form = document.querySelector(\"#form\");\nconst cpfField = document.querySelector(\"#cpf\");\nconst message = document.querySelector(\"#message\");\n\nform.addEventListener(\"submit\", function (event) {\n  event.preventDefault();\n\n  if (!validateCPF(cpfField.value)) {\n    message.textContent = \"Enter a valid CPF.\";\n    return;\n  }\n\n  message.textContent = \"Valid CPF.\";\n});\n",[68,961,962,989,1013,1037,1041,1069,1080,1084,1098,1115,1121,1125,1129,1145],{"__ignoreMap":66},[208,963,964,967,970,972,975,978,980,982,985,987],{"class":210,"line":211},[208,965,966],{"class":214},"const",[208,968,969],{"class":222}," form ",[208,971,246],{"class":214},[208,973,974],{"class":222}," document.",[208,976,977],{"class":218},"querySelector",[208,979,223],{"class":222},[208,981,787],{"class":276},[208,983,984],{"class":790},"#form",[208,986,787],{"class":276},[208,988,280],{"class":222},[208,990,991,993,996,998,1000,1002,1004,1006,1009,1011],{"class":210,"line":233},[208,992,966],{"class":214},[208,994,995],{"class":222}," cpfField ",[208,997,246],{"class":214},[208,999,974],{"class":222},[208,1001,977],{"class":218},[208,1003,223],{"class":222},[208,1005,787],{"class":276},[208,1007,1008],{"class":790},"#cpf",[208,1010,787],{"class":276},[208,1012,280],{"class":222},[208,1014,1015,1017,1020,1022,1024,1026,1028,1030,1033,1035],{"class":210,"line":240},[208,1016,966],{"class":214},[208,1018,1019],{"class":222}," message ",[208,1021,246],{"class":214},[208,1023,974],{"class":222},[208,1025,977],{"class":218},[208,1027,223],{"class":222},[208,1029,787],{"class":276},[208,1031,1032],{"class":790},"#message",[208,1034,787],{"class":276},[208,1036,280],{"class":222},[208,1038,1039],{"class":210,"line":283},[208,1040,287],{"emptyLinePlaceholder":286},[208,1042,1043,1046,1049,1051,1053,1056,1058,1060,1062,1064,1067],{"class":210,"line":290},[208,1044,1045],{"class":222},"form.",[208,1047,1048],{"class":218},"addEventListener",[208,1050,223],{"class":222},[208,1052,787],{"class":276},[208,1054,1055],{"class":790},"submit",[208,1057,787],{"class":276},[208,1059,273],{"class":222},[208,1061,215],{"class":214},[208,1063,347],{"class":222},[208,1065,1066],{"class":226},"event",[208,1068,230],{"class":222},[208,1070,1071,1074,1077],{"class":210,"line":296},[208,1072,1073],{"class":222},"  event.",[208,1075,1076],{"class":218},"preventDefault",[208,1078,1079],{"class":222},"();\n",[208,1081,1082],{"class":210,"line":313},[208,1083,287],{"emptyLinePlaceholder":286},[208,1085,1086,1088,1090,1093,1095],{"class":210,"line":325},[208,1087,299],{"class":214},[208,1089,347],{"class":222},[208,1091,1092],{"class":214},"!",[208,1094,782],{"class":218},[208,1096,1097],{"class":222},"(cpfField.value)) {\n",[208,1099,1100,1103,1105,1108,1111,1113],{"class":210,"line":331},[208,1101,1102],{"class":222},"    message.textContent ",[208,1104,246],{"class":214},[208,1106,1107],{"class":276}," \"",[208,1109,1110],{"class":790},"Enter a valid CPF.",[208,1112,787],{"class":276},[208,1114,322],{"class":222},[208,1116,1117,1119],{"class":210,"line":336},[208,1118,316],{"class":214},[208,1120,322],{"class":222},[208,1122,1123],{"class":210,"line":342},[208,1124,328],{"class":222},[208,1126,1127],{"class":210,"line":377},[208,1128,287],{"emptyLinePlaceholder":286},[208,1130,1131,1134,1136,1138,1141,1143],{"class":210,"line":386},[208,1132,1133],{"class":222},"  message.textContent ",[208,1135,246],{"class":214},[208,1137,1107],{"class":276},[208,1139,1140],{"class":790},"Valid CPF.",[208,1142,787],{"class":276},[208,1144,322],{"class":222},[208,1146,1147],{"class":210,"line":391},[208,1148,1149],{"class":222},"});\n",[16,1151,1152],{},"This validation improves the experience in the browser, but it does not replace validation on the server. Any code that runs on the front-end can be changed or skipped by the client. The back-end should repeat the validation before saving or processing the data.",[28,1154,1156],{"id":1155},"common-mistakes","Common mistakes",[52,1158,1160],{"id":1159},"validating-a-cpf-with-a-format-regex-only","Validating a CPF with a format regex only",[16,1162,1163],{},"An expression like this one:",[60,1165,1167],{"className":202,"code":1166,"language":204,"meta":66,"style":66},"\u002F^\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}$\u002F;\n",[68,1168,1169],{"__ignoreMap":66},[208,1170,1171,1173,1175,1177,1180,1183,1185,1187,1189,1191,1193,1196,1198,1201,1203],{"class":210,"line":211},[208,1172,261],{"class":260},[208,1174,352],{"class":214},[208,1176,358],{"class":264},[208,1178,1179],{"class":214},"{3}",[208,1181,1182],{"class":790},"\\.",[208,1184,358],{"class":264},[208,1186,1179],{"class":214},[208,1188,1182],{"class":790},[208,1190,358],{"class":264},[208,1192,1179],{"class":214},[208,1194,1195],{"class":790},"-",[208,1197,358],{"class":264},[208,1199,1200],{"class":214},"{2}$",[208,1202,261],{"class":260},[208,1204,322],{"class":222},[16,1206,1207,1208,1211],{},"only checks whether the text has the ",[68,1209,1210],{},"000.000.000-00"," format. It does not calculate the check digits.",[16,1213,1214,1215,1218],{},"For example, ",[68,1216,1217],{},"123.456.789-00"," can be perfectly formatted and still be an invalid CPF. A regex can help check what the input looks like, but it does not replace the CPF algorithm.",[52,1220,1222],{"id":1221},"forgetting-leading-zeros","Forgetting leading zeros",[16,1224,1225],{},"A CPF is an identifier, not a number for regular math. So treat it as a string.",[16,1227,1228,1229,1232],{},"If you convert a CPF to ",[68,1230,1231],{},"Number",", a value that starts with zero can lose that zero:",[60,1234,1236],{"className":202,"code":1235,"language":204,"meta":66,"style":66},"const cpf = Number(\"012.345.678-90\");\n",[68,1237,1238],{"__ignoreMap":66},[208,1239,1240,1242,1245,1247,1249,1251,1253,1256,1258],{"class":210,"line":211},[208,1241,966],{"class":214},[208,1243,1244],{"class":222}," cpf ",[208,1246,246],{"class":214},[208,1248,467],{"class":218},[208,1250,223],{"class":222},[208,1252,787],{"class":276},[208,1254,1255],{"class":790},"012.345.678-90",[208,1257,787],{"class":276},[208,1259,280],{"class":222},[16,1261,1262,1263,1266],{},"Also, very large numbers should not be the main representation of documents. The function in this article converts the input to text with ",[68,1264,1265],{},"String(cpf)"," and removes the formatting before calculating.",[16,1268,1269],{},"In practice, keep the value from the HTML field as a string from the start.",[52,1271,1273],{"id":1272},"not-normalizing-the-input","Not normalizing the input",[16,1275,1276],{},"If the code expects exactly 11 digits, it may reject a formatted CPF before it even runs the calculation.",[16,1278,1279],{},"This step fixes the problem:",[60,1281,1283],{"className":202,"code":1282,"language":204,"meta":66,"style":66},"cpf = String(cpf).replace(\u002F\\D\u002Fg, \"\");\n",[68,1284,1285],{"__ignoreMap":66},[208,1286,1287,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312],{"class":210,"line":211},[208,1288,1289],{"class":222},"cpf ",[208,1291,246],{"class":214},[208,1293,249],{"class":218},[208,1295,252],{"class":222},[208,1297,255],{"class":218},[208,1299,223],{"class":222},[208,1301,261],{"class":260},[208,1303,265],{"class":264},[208,1305,261],{"class":260},[208,1307,270],{"class":214},[208,1309,273],{"class":222},[208,1311,277],{"class":276},[208,1313,280],{"class":222},[16,1315,1316],{},"It removes dots, dashes, spaces and other non-numeric characters. After that, the function checks whether exactly 11 digits are left.",[52,1318,1320],{"id":1319},"validating-only-in-the-browser","Validating only in the browser",[16,1322,1323],{},"Front-end validation is useful for instant feedback, but it is not a security layer. A user can send a request straight to the server without going through the page's JavaScript.",[16,1325,1326],{},"The same rule should exist on the back-end, preferably in a single function covered by tests.",[28,1328,1330],{"id":1329},"frequently-asked-questions","Frequently asked questions",[52,1332,1334],{"id":1333},"how-do-i-know-if-a-cpf-is-valid","How do I know if a CPF is valid?",[16,1336,1337],{},"First, remove the dots and dash and confirm that 11 digits are left. Then reject sequences with all digits equal and calculate the two check digits according to the CPF algorithm.",[16,1339,1340,1341,1344],{},"The CPF is only mathematically valid if the two calculated digits match the last two digits provided. The ",[68,1342,1343],{},"validateCPF(cpf)"," function in this article runs all of these steps.",[16,1346,1347],{},"Passing the math check says nothing about whether the document is active, in good standing or tied to a specific person.",[52,1349,1351],{"id":1350},"how-do-i-calculate-the-cpf-check-digit","How do I calculate the CPF check digit?",[16,1353,1354],{},"For the first digit, multiply the 9 base digits by the weights from 10 down to 2. Add up the results and calculate the remainder of the division by 11.",[36,1356,1357,1363],{},[39,1358,1359,1360,121],{},"If the remainder is 0 or 1, the digit is ",[68,1361,1362],{},"0",[39,1364,1365,1366,121],{},"Otherwise, the digit is ",[68,1367,1368],{},"11 - remainder",[16,1370,1371],{},"For the second digit, do the same with the first 10 digits and the weights from 11 down to 2.",[16,1373,1374],{},"In JavaScript, the core of the calculation can be written like this:",[60,1376,1378],{"className":202,"code":1377,"language":204,"meta":66,"style":66},"const digit = remainder \u003C 2 ? 0 : 11 - remainder;\n",[68,1379,1380],{"__ignoreMap":66},[208,1381,1382,1384,1387,1389,1391,1393,1395,1397,1399,1401,1403,1405],{"class":210,"line":211},[208,1383,966],{"class":214},[208,1385,1386],{"class":222}," digit ",[208,1388,246],{"class":214},[208,1390,502],{"class":222},[208,1392,444],{"class":214},[208,1394,531],{"class":264},[208,1396,534],{"class":214},[208,1398,413],{"class":264},[208,1400,539],{"class":214},[208,1402,308],{"class":264},[208,1404,481],{"class":214},[208,1406,546],{"class":222},[52,1408,1410],{"id":1409},"is-validating-a-cpf-the-same-as-checking-it-with-the-receita-federal","Is validating a CPF the same as checking it with the Receita Federal?",[16,1412,1413],{},"No. The math check runs locally: the system calculates the digits and compares the result with the CPF provided.",[16,1415,1416],{},"An official lookup is a different operation. It can check registration details and the status of the CPF in an official database, usually through an authorized service or the channels the Receita Federal provides.",[16,1418,1419],{},"So a CPF can pass the algorithm and still not be in good standing, not exist in the database you checked or not belong to the person who entered it. The JavaScript code does not confirm identity or registration status.",[52,1421,1423],{"id":1422},"can-i-generate-a-valid-cpf-for-testing","Can I generate a valid CPF for testing?",[16,1425,1426,1427,1432],{},"Yes. To test input masks, forms and APIs, you can use numbers that pass the math check without using real data. If you need valid CPF numbers just to test forms, ",[944,1428,1431],{"href":1429,"rel":1430},"https:\u002F\u002Fcodigoaoponto.com\u002Fen\u002Ftools\u002Fcpf-generator",[948],"our CPF generator"," handles that in seconds.",[16,1434,1435],{},"Use test data in a controlled way and make it clear, in your team's environment, that it is fictional. Also avoid putting real documents in public examples, test files or repositories.",[52,1437,1439],{"id":1438},"does-the-function-check-whether-the-cpf-belongs-to-the-user","Does the function check whether the CPF belongs to the user?",[16,1441,1442],{},"No. It only checks the normalized format, the number of digits, the check digit rule and the rejection of repeated sequences.",[16,1444,1445],{},"To confirm ownership, you would need a different step, with an official source or a proper verification flow. Local validation does not replace that process.",[28,1447,1449],{"id":1448},"next-steps","Next steps",[16,1451,1452,1453,1455],{},"You now have the CPF algorithm and a ",[68,1454,1343],{}," function ready to adapt to your project. Put the validation on the front-end to guide the user and repeat the rule on the back-end before storing or accepting the sign-up.",[16,1457,1458,1459,1463],{},"If you want to check values without writing code, use ",[944,1460,1462],{"href":946,"rel":1461},[948],"our online CPF checker",". After that, it is worth turning the examples in this article into automated tests that cover formatted input, invalid CPFs and documents with leading zeros.",[1465,1466,1467],"style",{},"html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .sGEwX, html code.shiki .sGEwX{--shiki-default:#FFB86C;--shiki-default-font-style:italic}html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}html pre.shiki code .s-doY, html code.shiki .s-doY{--shiki-default:#FF5555}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .smvxG, html code.shiki .smvxG{--shiki-default:#FFB86C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}",{"title":66,"searchDepth":233,"depth":233,"links":1469},[1470,1474,1477,1483,1490],{"id":30,"depth":233,"text":31,"children":1471},[1472,1473],{"id":54,"depth":240,"text":55},{"id":124,"depth":240,"text":125},{"id":188,"depth":233,"text":189,"children":1475},[1476],{"id":952,"depth":240,"text":953},{"id":1155,"depth":233,"text":1156,"children":1478},[1479,1480,1481,1482],{"id":1159,"depth":240,"text":1160},{"id":1221,"depth":240,"text":1222},{"id":1272,"depth":240,"text":1273},{"id":1319,"depth":240,"text":1320},{"id":1329,"depth":233,"text":1330,"children":1484},[1485,1486,1487,1488,1489],{"id":1333,"depth":240,"text":1334},{"id":1350,"depth":240,"text":1351},{"id":1409,"depth":240,"text":1410},{"id":1422,"depth":240,"text":1423},{"id":1438,"depth":240,"text":1439},{"id":1448,"depth":233,"text":1449},[204,1492],"tools","Learn how to validate a CPF with plain JavaScript, calculate the check digits, handle formatting and reject invalid sequences in forms, with working code.","how-to-validate-cpf-with-javascript","md",{},"\u002Fen\u002Fblog\u002Fhow-to-validate-cpf-with-javascript","como-validar-cpf-com-javascript","2026-10-04",{"title":6,"description":1493},{"loc":1497,"lastmod":1502},"2026-10-06","en\u002Fblog\u002Fhow-to-validate-cpf-with-javascript",1253,"rl6GsOytKht8bBLg9yWipV1zFDvkHy7ruCKxlllBid0",{"id":1507,"title":1508,"articleCover":1509,"articleCoverEmbed":8,"articleCoverEmbedUploadDate":8,"articleCoverHeight":9,"articleCoverWidth":10,"authorId":11,"body":1510,"categoriesIds":2252,"description":2253,"enAlternateSlug":2254,"extension":1495,"meta":2255,"navigation":286,"path":2256,"ptBrAlternateSlug":2257,"publishedAt":1499,"seo":2258,"sitemap":2259,"stem":2260,"updatedAt":1499,"wordCount":2261,"__hash__":2262},"blogEn\u002Fen\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript.md","How to validate a credit card with JavaScript (Luhn algorithm)","\u002Fimages\u002Fen\u002Fblog\u002Fjavascript\u002Fhow-to-validate-credit-card-with-javascript.webp",{"type":13,"value":1511,"toc":2229},[1512,1515,1518,1522,1529,1532,1535,1539,1549,1552,1585,1589,1604,1630,1636,1639,1641,1644,2041,2058,2062,2073,2090,2096,2099,2101,2104,2108,2115,2119,2132,2136,2139,2143,2150,2159,2161,2165,2176,2180,2183,2187,2190,2194,2197,2201,2204,2208,2211,2215,2218,2226],[16,1513,1514],{},"You are building a checkout form and need to validate the card field before sending the data to the payment gateway. The most common and recommended approach is to use the Luhn algorithm to check whether the number has the correct mathematical format.",[16,1516,1517],{},"In this article, you will understand exactly how the algorithm works, follow a step-by-step numeric example and implement a JavaScript function ready to use in your project.",[28,1519,1521],{"id":1520},"what-the-luhn-algorithm-is","What the Luhn algorithm is",[16,1523,1524,1525,1528],{},"The Luhn algorithm, also called the \"modulus 10 formula\" or \"mod-10\", was created by Hans Peter Luhn in 1954 and became the industry standard for validating credit card numbers. It calculates a ",[23,1526,1527],{},"check digit"," (the last digit of the number) that catches typing errors, like swapping two digits or typing a wrong number.",[16,1530,1531],{},"The idea is simple: the card issuer (bank or card network) generates the number so that, when you apply the Luhn formula, the result is divisible by 10. If it is not, the number has a formatting error.",[16,1533,1534],{},"This runs on the client side (in the browser) before the data goes to the server. That way you avoid sending invalid requests to the payment gateway and improve the user experience with instant feedback.",[28,1536,1538],{"id":1537},"the-algorithm-step-by-step-with-a-numeric-example","The algorithm step by step with a numeric example",[16,1540,1541,1542,1545,1546,121],{},"Let's validate the Visa test number that many payment platforms use in sandbox: ",[23,1543,1544],{},"4242 4242 4242 4242",". First, we remove spaces and dashes, which leaves ",[68,1547,1548],{},"4242424242424242",[16,1550,1551],{},"Now we apply the Luhn algorithm:",[1553,1554,1555,1561,1567,1573,1579],"ol",{},[39,1556,1557,1560],{},[23,1558,1559],{},"Start from the rightmost digit"," (the last 2) and move left. This first digit is never doubled.",[39,1562,1563,1566],{},[23,1564,1565],{},"Double the value of every second digit"," from there, that is, skip one, double the next, skip one, double the next, and so on.",[39,1568,1569,1572],{},[23,1570,1571],{},"If doubling gives a two-digit result",", add the two digits together (or subtract 9, which is equivalent).",[39,1574,1575,1578],{},[23,1576,1577],{},"Add up all the digits"," (the doubled\u002Fadjusted ones and the ones left unchanged).",[39,1580,1581,1584],{},[23,1582,1583],{},"If the total is divisible by 10",", the number is valid according to the Luhn algorithm.",[52,1586,1588],{"id":1587},"hands-on-example-with-4242424242424242","Hands-on example with 4242424242424242",[16,1590,1591,1592,898,1595,1597,1598,1600,1601,1603],{},"The number has 16 digits, alternating ",[68,1593,1594],{},"4",[68,1596,120],{},". Starting from the rightmost digit (which is not doubled) and moving left, the digits in the \"double\" position are always the ",[68,1599,1594],{},"s, and the ones in the \"don't double\" position are always the ",[68,1602,120],{},"s. That happens because the whole number follows this alternating pattern.",[36,1605,1606,1615],{},[39,1607,1608,1611,1612,1614],{},[23,1609,1610],{},"Digits that are not doubled"," (8 digits, all ",[68,1613,120],{},"): 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 = 16",[39,1616,1617,1611,1620,1622,1623,1625,1626,1629],{},[23,1618,1619],{},"Doubled digits",[68,1621,1594],{},"): each doubled ",[68,1624,1594],{}," becomes ",[68,1627,1628],{},"8"," (4 × 2 = 8, not above 9, no adjustment needed). 8 + 8 + 8 + 8 + 8 + 8 + 8 + 8 = 64",[16,1631,1632,1633,121],{},"Adding the two groups: 16 + 64 = ",[23,1634,1635],{},"80",[16,1637,1638],{},"Since 80 is divisible by 10 (remainder 0), this number passes the Luhn check.",[28,1640,189],{"id":188},[16,1642,1643],{},"Below is a complete function that removes spaces, dashes and other non-numeric characters, then applies the Luhn algorithm:",[60,1645,1647],{"className":202,"code":1646,"language":204,"meta":66,"style":66},"function validateCreditCard(number) {\n  \u002F\u002F Remove everything that is not a digit\n  const digits = number.replace(\u002F\\D\u002Fg, \"\");\n\n  \u002F\u002F Cards have between 13 and 19 digits (most have 16)\n  if (digits.length \u003C 13 || digits.length > 19) {\n    return false;\n  }\n\n  let sum = 0;\n  let shouldDouble = false; \u002F\u002F starts at the last digit (not doubled)\n\n  \u002F\u002F Walk from right to left\n  for (let i = digits.length - 1; i >= 0; i--) {\n    let d = parseInt(digits[i], 10);\n\n    if (shouldDouble) {\n      d *= 2;\n      \u002F\u002F If the result has two digits, add them up (or subtract 9)\n      if (d > 9) {\n        d -= 9;\n      }\n    }\n\n    sum += d;\n    shouldDouble = !shouldDouble; \u002F\u002F alternate for the next digit\n  }\n\n  return sum % 10 === 0;\n}\n\n\u002F\u002F Testing with the Visa test number\nconsole.log(validateCreditCard(\"4242 4242 4242 4242\")); \u002F\u002F true\nconsole.log(validateCreditCard(\"4242424242424242\")); \u002F\u002F true\nconsole.log(validateCreditCard(\"1234 5678 1234 5678\")); \u002F\u002F false\n",[68,1648,1649,1663,1668,1698,1702,1707,1733,1741,1745,1749,1761,1778,1782,1787,1820,1840,1844,1852,1864,1869,1883,1895,1900,1905,1909,1918,1934,1938,1942,1959,1963,1967,1972,1996,2018],{"__ignoreMap":66},[208,1650,1651,1653,1656,1658,1661],{"class":210,"line":211},[208,1652,215],{"class":214},[208,1654,1655],{"class":218}," validateCreditCard",[208,1657,223],{"class":222},[208,1659,1660],{"class":226},"number",[208,1662,230],{"class":222},[208,1664,1665],{"class":210,"line":233},[208,1666,1667],{"class":236},"  \u002F\u002F Remove everything that is not a digit\n",[208,1669,1670,1672,1675,1677,1680,1682,1684,1686,1688,1690,1692,1694,1696],{"class":210,"line":240},[208,1671,519],{"class":214},[208,1673,1674],{"class":222}," digits ",[208,1676,246],{"class":214},[208,1678,1679],{"class":222}," number.",[208,1681,255],{"class":218},[208,1683,223],{"class":222},[208,1685,261],{"class":260},[208,1687,265],{"class":264},[208,1689,261],{"class":260},[208,1691,270],{"class":214},[208,1693,273],{"class":222},[208,1695,277],{"class":276},[208,1697,280],{"class":222},[208,1699,1700],{"class":210,"line":283},[208,1701,287],{"emptyLinePlaceholder":286},[208,1703,1704],{"class":210,"line":290},[208,1705,1706],{"class":236},"  \u002F\u002F Cards have between 13 and 19 digits (most have 16)\n",[208,1708,1709,1711,1714,1716,1719,1722,1725,1728,1731],{"class":210,"line":296},[208,1710,299],{"class":214},[208,1712,1713],{"class":222}," (digits.length ",[208,1715,444],{"class":214},[208,1717,1718],{"class":264}," 13",[208,1720,1721],{"class":214}," ||",[208,1723,1724],{"class":222}," digits.length ",[208,1726,1727],{"class":214},">",[208,1729,1730],{"class":264}," 19",[208,1732,230],{"class":222},[208,1734,1735,1737,1739],{"class":210,"line":313},[208,1736,316],{"class":214},[208,1738,319],{"class":264},[208,1740,322],{"class":222},[208,1742,1743],{"class":210,"line":325},[208,1744,328],{"class":222},[208,1746,1747],{"class":210,"line":331},[208,1748,287],{"emptyLinePlaceholder":286},[208,1750,1751,1753,1755,1757,1759],{"class":210,"line":336},[208,1752,405],{"class":214},[208,1754,408],{"class":222},[208,1756,246],{"class":214},[208,1758,413],{"class":264},[208,1760,322],{"class":222},[208,1762,1763,1765,1768,1770,1772,1775],{"class":210,"line":342},[208,1764,405],{"class":214},[208,1766,1767],{"class":222}," shouldDouble ",[208,1769,246],{"class":214},[208,1771,319],{"class":264},[208,1773,1774],{"class":222},"; ",[208,1776,1777],{"class":236},"\u002F\u002F starts at the last digit (not doubled)\n",[208,1779,1780],{"class":210,"line":377},[208,1781,287],{"emptyLinePlaceholder":286},[208,1783,1784],{"class":210,"line":386},[208,1785,1786],{"class":236},"  \u002F\u002F Walk from right to left\n",[208,1788,1789,1791,1793,1795,1797,1799,1801,1803,1806,1808,1811,1813,1815,1818],{"class":210,"line":391},[208,1790,426],{"class":214},[208,1792,347],{"class":222},[208,1794,431],{"class":214},[208,1796,434],{"class":222},[208,1798,246],{"class":214},[208,1800,1724],{"class":222},[208,1802,1195],{"class":214},[208,1804,1805],{"class":264}," 1",[208,1807,441],{"class":222},[208,1809,1810],{"class":214},">=",[208,1812,413],{"class":264},[208,1814,450],{"class":222},[208,1816,1817],{"class":214},"--",[208,1819,230],{"class":222},[208,1821,1822,1825,1828,1830,1833,1836,1838],{"class":210,"line":396},[208,1823,1824],{"class":214},"    let",[208,1826,1827],{"class":222}," d ",[208,1829,246],{"class":214},[208,1831,1832],{"class":218}," parseInt",[208,1834,1835],{"class":222},"(digits[i], ",[208,1837,478],{"class":264},[208,1839,280],{"class":222},[208,1841,1842],{"class":210,"line":402},[208,1843,287],{"emptyLinePlaceholder":286},[208,1845,1846,1849],{"class":210,"line":418},[208,1847,1848],{"class":214},"    if",[208,1850,1851],{"class":222}," (shouldDouble) {\n",[208,1853,1854,1857,1860,1862],{"class":210,"line":423},[208,1855,1856],{"class":222},"      d ",[208,1858,1859],{"class":214},"*=",[208,1861,531],{"class":264},[208,1863,322],{"class":222},[208,1865,1866],{"class":210,"line":458},[208,1867,1868],{"class":236},"      \u002F\u002F If the result has two digits, add them up (or subtract 9)\n",[208,1870,1871,1874,1877,1879,1881],{"class":210,"line":487},[208,1872,1873],{"class":214},"      if",[208,1875,1876],{"class":222}," (d ",[208,1878,1727],{"class":214},[208,1880,447],{"class":264},[208,1882,230],{"class":222},[208,1884,1885,1888,1891,1893],{"class":210,"line":492},[208,1886,1887],{"class":222},"        d ",[208,1889,1890],{"class":214},"-=",[208,1892,447],{"class":264},[208,1894,322],{"class":222},[208,1896,1897],{"class":210,"line":497},[208,1898,1899],{"class":222},"      }\n",[208,1901,1902],{"class":210,"line":516},[208,1903,1904],{"class":222},"    }\n",[208,1906,1907],{"class":210,"line":549},[208,1908,287],{"emptyLinePlaceholder":286},[208,1910,1911,1913,1915],{"class":210,"line":554},[208,1912,461],{"class":222},[208,1914,464],{"class":214},[208,1916,1917],{"class":222}," d;\n",[208,1919,1920,1923,1925,1928,1931],{"class":210,"line":560},[208,1921,1922],{"class":222},"    shouldDouble ",[208,1924,246],{"class":214},[208,1926,1927],{"class":214}," !",[208,1929,1930],{"class":222},"shouldDouble; ",[208,1932,1933],{"class":236},"\u002F\u002F alternate for the next digit\n",[208,1935,1936],{"class":210,"line":581},[208,1937,328],{"class":222},[208,1939,1940],{"class":210,"line":590},[208,1941,287],{"emptyLinePlaceholder":286},[208,1943,1944,1946,1948,1950,1952,1955,1957],{"class":210,"line":595},[208,1945,741],{"class":214},[208,1947,408],{"class":222},[208,1949,509],{"class":214},[208,1951,642],{"class":264},[208,1953,1954],{"class":214}," ===",[208,1956,413],{"class":264},[208,1958,322],{"class":222},[208,1960,1961],{"class":210,"line":600},[208,1962,761],{"class":222},[208,1964,1965],{"class":210,"line":606},[208,1966,287],{"emptyLinePlaceholder":286},[208,1968,1969],{"class":210,"line":618},[208,1970,1971],{"class":236},"\u002F\u002F Testing with the Visa test number\n",[208,1973,1974,1976,1978,1980,1983,1985,1987,1989,1991,1994],{"class":210,"line":623},[208,1975,774],{"class":222},[208,1977,777],{"class":218},[208,1979,223],{"class":222},[208,1981,1982],{"class":218},"validateCreditCard",[208,1984,223],{"class":222},[208,1986,787],{"class":276},[208,1988,1544],{"class":790},[208,1990,787],{"class":276},[208,1992,1993],{"class":222},")); ",[208,1995,800],{"class":236},[208,1997,1998,2000,2002,2004,2006,2008,2010,2012,2014,2016],{"class":210,"line":651},[208,1999,774],{"class":222},[208,2001,777],{"class":218},[208,2003,223],{"class":222},[208,2005,1982],{"class":218},[208,2007,223],{"class":222},[208,2009,787],{"class":276},[208,2011,1548],{"class":790},[208,2013,787],{"class":276},[208,2015,1993],{"class":222},[208,2017,800],{"class":236},[208,2019,2020,2022,2024,2026,2028,2030,2032,2035,2037,2039],{"class":210,"line":673},[208,2021,774],{"class":222},[208,2023,777],{"class":218},[208,2025,223],{"class":222},[208,2027,1982],{"class":218},[208,2029,223],{"class":222},[208,2031,787],{"class":276},[208,2033,2034],{"class":790},"1234 5678 1234 5678",[208,2036,787],{"class":276},[208,2038,1993],{"class":222},[208,2040,859],{"class":236},[16,2042,2043,2044,2047,2048,2051,2052,2057],{},"This is the function you call in your form's ",[68,2045,2046],{},"onblur"," or ",[68,2049,2050],{},"onsubmit",". If you want to test online before integrating it, we have a ",[944,2053,2056],{"href":2054,"rel":2055},"https:\u002F\u002Fcodigoaoponto.com\u002Fen\u002Ftools\u002Fcredit-card-validator",[948],"free online credit card validator"," that applies exactly this logic.",[28,2059,2061],{"id":2060},"what-this-algorithm-does-not-guarantee","What this algorithm does NOT guarantee",[16,2063,2064,2065,2068,2069,2072],{},"Many people skip this disclaimer and regret it later: ",[23,2066,2067],{},"the Luhn algorithm only validates the FORMAT\u002Fmathematical structure of the number",". It does ",[23,2070,2071],{},"NOT"," check:",[36,2074,2075,2078,2081,2084,2087],{},[39,2076,2077],{},"Whether the card actually exists",[39,2079,2080],{},"Whether it is active or blocked",[39,2082,2083],{},"Whether it has available credit",[39,2085,2086],{},"Whether it belongs to the person filling in the form",[39,2088,2089],{},"Whether it has been reported as stolen or used for fraud",[16,2091,2092,2093,2095],{},"Only the card issuer (bank or card network) can check that, through a real payment gateway (Stripe, Pagar.me, Mercado Pago, etc.). Luhn is just a \"typo filter\". It keeps you from sending ",[68,2094,2034],{}," to the gateway and getting a silly error that could have been caught earlier.",[16,2097,2098],{},"Don't write anything in your code suggesting that passing Luhn means \"a card you can charge\", because that is not true.",[28,2100,1156],{"id":1155},[16,2102,2103],{},"If you have implemented card validation before, you have probably seen (or made) one of these:",[52,2105,2107],{"id":2106},"validating-by-digit-count-only","Validating by digit count only",[16,2109,2110,2111,2114],{},"Many forms only check whether the number has 16 digits. That lets ",[68,2112,2113],{},"1111111111111111"," through, which has 16 digits but fails Luhn. The opposite also happens: American Express cards have 15 digits, so a \"must have 16\" rule breaks the flow for Amex users.",[52,2116,2118],{"id":2117},"not-removing-spacesdashes-before-validating","Not removing spaces\u002Fdashes before validating",[16,2120,2121,2122,2047,2125,2127,2128,2131],{},"The user types ",[68,2123,2124],{},"4242-4242-4242-4242",[68,2126,1544],{},". If you don't clean that up before applying Luhn, validation fails even with the correct number. The line ",[68,2129,2130],{},"number.replace(\u002F\\D\u002Fg, '')"," solves this.",[52,2133,2135],{"id":2134},"treating-luhn-as-a-fraud-check","Treating Luhn as a fraud check",[16,2137,2138],{},"This one is classic: the product team asks to \"check if the card is valid\" and the dev implements Luhn thinking it is a fraud check, which it is not. Fraud prevention requires risk analysis, tokenization, 3D Secure and gateway rules.",[52,2140,2142],{"id":2141},"using-test-numbers-as-if-they-were-real","Using test numbers as if they were real",[16,2144,2145,2146,2149],{},"The test numbers that gateways like Stripe and PayPal provide pass Luhn, but ",[23,2147,2148],{},"they are not real cards",". They only work in a sandbox environment. Never use them in production and never try to \"see if it works\" on a real gateway. That violates the terms and can get your account blocked.",[16,2151,2152,2153,2158],{},"If you need Luhn-valid test data for your forms, our ",[944,2154,2157],{"href":2155,"rel":2156},"https:\u002F\u002Fcodigoaoponto.com\u002Fen\u002Ftools\u002Fcredit-card-generator",[948],"credit card generator for testing"," creates structurally correct (but not real) numbers for you to use in QA.",[28,2160,1330],{"id":1329},[52,2162,2164],{"id":2163},"how-do-i-know-if-a-card-number-is-valid","How do I know if a card number is valid?",[16,2166,2167,2168,2171,2172,2175],{},"It depends on what you mean by \"valid\". If you mean ",[23,2169,2170],{},"correct format",", use the Luhn algorithm, which is what most gateways expect on the front-end. If you mean ",[23,2173,2174],{},"a card that actually works",", only the payment gateway (through the issuer) can answer that, after you try to charge it.",[52,2177,2179],{"id":2178},"can-i-test-a-payment-form-without-a-real-card","Can I test a payment form without a real card?",[16,2181,2182],{},"Yes. Use the test numbers each gateway provides (Stripe, Pagar.me, Mercado Pago, etc.). They pass Luhn and simulate scenarios like \"payment approved\", \"insufficient funds\", \"3D Secure\", etc. Never use other people's real cards. Use only the sandbox ones.",[52,2184,2186],{"id":2185},"is-validating-a-credit-card-the-same-as-checking-whether-it-is-active","Is validating a credit card the same as checking whether it is active?",[16,2188,2189],{},"No. Validating (with Luhn) checks whether the number has the correct mathematical structure. Checking whether it is active, has credit or is not blocked is the bank's job, done through the gateway when you try to process the payment.",[52,2191,2193],{"id":2192},"what-is-the-luhn-algorithm","What is the Luhn algorithm?",[16,2195,2196],{},"It is a math formula (modulus 10) that calculates a check digit to catch typing errors in numbers like credit cards, phone IMEIs, etc. Hans Peter Luhn created it in 1954 and it became the industry standard.",[52,2198,2200],{"id":2199},"can-i-use-luhn-to-prevent-fraud","Can I use Luhn to prevent fraud?",[16,2202,2203],{},"No. Luhn only catches typos, while fraud prevention requires behavioral analysis, address verification, 3D Secure and the gateway's risk rules.",[52,2205,2207],{"id":2206},"what-is-the-difference-between-luhn-valid-number-and-card-you-can-charge","What is the difference between \"Luhn-valid number\" and \"card you can charge\"?",[16,2209,2210],{},"\"Luhn-valid number\" means correct mathematical format. \"Card you can charge\" means the issuer confirmed the card exists, is active, has credit and is not blocked. Only the gateway, together with the issuer, can answer the second question.",[28,2212,2214],{"id":2213},"wrapping-up","Wrapping up",[16,2216,2217],{},"If you are implementing card validation in a checkout form, the Luhn algorithm is the first step, and the most important one, to avoid silly typing errors. Implement the function above, test it with your gateway's sandbox numbers and always remember: Luhn validates the format, not whether the card actually works.",[16,2219,2220,2221,2225],{},"Want to test your implementation before shipping to production? Try our ",[944,2222,2224],{"href":2054,"rel":2223},[948],"online credit card validator",". It applies exactly the same logic you will use in your code.",[1465,2227,2228],{},"html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .sGEwX, html code.shiki .sGEwX{--shiki-default:#FFB86C;--shiki-default-font-style:italic}html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}html pre.shiki code .s-doY, html code.shiki .s-doY{--shiki-default:#FF5555}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":66,"searchDepth":233,"depth":233,"links":2230},[2231,2232,2235,2236,2237,2243,2251],{"id":1520,"depth":233,"text":1521},{"id":1537,"depth":233,"text":1538,"children":2233},[2234],{"id":1587,"depth":240,"text":1588},{"id":188,"depth":233,"text":189},{"id":2060,"depth":233,"text":2061},{"id":1155,"depth":233,"text":1156,"children":2238},[2239,2240,2241,2242],{"id":2106,"depth":240,"text":2107},{"id":2117,"depth":240,"text":2118},{"id":2134,"depth":240,"text":2135},{"id":2141,"depth":240,"text":2142},{"id":1329,"depth":233,"text":1330,"children":2244},[2245,2246,2247,2248,2249,2250],{"id":2163,"depth":240,"text":2164},{"id":2178,"depth":240,"text":2179},{"id":2185,"depth":240,"text":2186},{"id":2192,"depth":240,"text":2193},{"id":2199,"depth":240,"text":2200},{"id":2206,"depth":240,"text":2207},{"id":2213,"depth":233,"text":2214},[204,1492],"Learn how to validate a credit card number with JavaScript using the Luhn algorithm. A hands-on example, ready-to-use code and what Luhn does not check.","how-to-validate-credit-card-with-javascript",{},"\u002Fen\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript","como-validar-cartao-de-credito-com-javascript",{"title":1508,"description":2253},{"loc":2256,"lastmod":1499},"en\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript",1317,"5gPXkTWBxMl6Rgba4_I126Dm2nIZeJpZMh9Vi5n2Zpc",1791682337472]