credit-card-type and the case for detecting brands from partial numbers
A library for determining credit card type
At a glance
- What is it?
- credit-card-type is a small npm library from Braintree that tells you which card brand a partial or full number belongs to, along with the gaps, lengths and security code name a checkout form needs. It is explicitly not a validation library, and it is a CommonJS package built from TypeScript sources.
- Who is it for?
- Adopt credit-card-type if you are building a card input that should adapt its formatting and its security code label as the user types, and if you would rather not maintain a brand pattern table yourself. Do not adopt it expecting validation: it does not check a checksum, and it returns an empty array for a number that matches nothing, so you still need a luhn check and your own rejection rules.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Type-as-you-go is the design constraint, not a feature list
credit-card-type is a library for determining a credit card type from fully qualified and partial numbers. The README is explicit about what it is not: this is not a validation library, but a smaller component to help you build your own validation or UI library.
That sentence is the whole product in one line, and it explains the API. A checkout form that asks for sixteen digits should decide after the first keystroke whether to format the input as four groups, whether to show sixteen boxes or nineteen, and whether to label the security code CVV, CVC or CID. Waiting for a complete number before deciding any of that is a worse user experience, and waiting for a full number before you can even label the field is worse still.
So the library is designed for type-as-you-go detection with support for partial numbers, and it is written in CommonJS so it can be used in Node, io.js and the browser. The audience is the engineer assembling a payment form who needs the brand rules but does not want to own them.
The return value is an array because one digit can mean six brands
Calling the library returns an array of objects, and the array is not an implementation detail. The README example asks for the type of a Visa number:
var creditCardType = require("credit-card-type");
var visaCards = creditCardType("4111");
console.log(visaCards[0].type); // 'visa'And then it asks about a single ambiguous digit:
var ambiguousCards = creditCardType("6");
console.log(ambiguousCards.length); // 6
console.log(ambiguousCards[0].niceType); // 'Discover'
console.log(ambiguousCards[1].niceType); // 'UnionPay'
console.log(ambiguousCards[2].niceType); // 'Maestro'Six brand patterns start with a six, so the honest answer at that point is six possible brands, and the library gives you all of them rather than picking one. If nothing matches, the return is an empty array.
That shapes how you write the calling code. A form that wants to show a brand icon as the user types has to decide what to do with several candidates, and a form that only wants to adjust formatting can usually ignore all but the first, since the gaps and lengths of the candidates may well agree at that point. Treating the first entry as the answer without checking the length of the array is the mistake this API is designed to make obvious.
gaps and lengths are what a form actually consumes
Each returned object carries a niceType, which is a pretty printed brand name such as Visa, Mastercard, American Express, Diners Club, Discover, JCB, UnionPay, Maestro, Mir, Elo, Hiper, Hipercard, Verve, Naranja or Troy. The type field is the code friendly version, useful as a CSS class name, with values like visa, mastercard, american-express, diners-club, discover, jcb, unionpay, maestro, mir, elo, hiper, hipercard, verve, naranja and troy.
The two fields that do the real work in a form are gaps and lengths. gaps is the array of expected indices where a space belongs in the printed form, so a Visa number printed as 4111 1111 1111 1111 has gaps at the 4th, 8th and 12th positions. lengths is the array of expected lengths of the number, excluding spaces and slashes.
Because lengths is an array rather than a single number, the library can express brands that have more than one valid length, and because gaps is positional, a form can insert separators as the user types without reformatting from scratch. The README notes the card number should be normalized before use, with no letters or special characters, which is a small requirement that pays off because the pattern matching then has less to reason about.
The code object carries the security code name and size
Card brands do not agree on what the three or four digit security code is called, and they do not agree on its length either. The library encodes that in a code object with a name and a size, and the README tabulates it per brand: Visa uses CVV of size 3, Mastercard CVC of size 3, American Express CID of size 4, Diners Club CVV of 3, Discover CID of 3, JCB CVV of 3, UnionPay CVN of 3, Maestro CVC of 3, Mir CVP2 of 3, Elo CVE of 3, Hiper CVC of 3, Hipercard CVC of 4, Verve CVV of 3, Naranja CVV of 3 and Troy CVV of 3.
A full response for a Visa card looks like this:
{
"niceType": "Visa",
"type": "visa",
"gaps": [4, 8, 12],
"lengths": [16],
"code": { "name": "CVV", "size": 3 }
}The practical value is the label and the input length of the security code field, both of which you can set the moment the brand is known. The value it does not carry is validation of that code. Nothing here tells you whether the digits the user typed are correct, only what the field should look like.
Named constants and getTypeInfo for the single brand case
Two conveniences exist for code that does not need the array behaviour. getTypeInfo takes a type string and returns a single object with the same structure, or undefined if the type is invalid or unknown, which is the right call when you already know the brand and just want its gaps, lengths and code.
There are also named constants for every supported brand, listed in the README as AMERICAN_EXPRESS, DINERS_CLUB, DISCOVER, ELO, HIPERCARD, HIPER, JCB, MAESTRO, MASTERCARD, MIR, UNIONPAY, VISA, VERVE, NARANJA and TROY. They are exported as types, and the filtering example in the README shows the intended use, narrowing a result set to two brands:
creditCardType(cardNumber).filter(function (card) {
return card.type === CardType.MASTERCARD || card.type === CardType.VISA;
});The module can be consumed in either module system. The CommonJS form exposes the function plus getTypeInfo and types as separate requires, while the ES6 form imports them as named exports:
import creditCardType, {
getTypeInfo,
types as CardType,
} from "credit-card-type";Using the constants instead of raw strings matters more than it looks, because a typo in a string literal is a silent failure while a wrong constant is a build error.
TypeScript sources, CommonJS output, and a coverage gate at 80 percent
The repository is written in TypeScript even though the README describes the package as CommonJS, and the package manifest explains the split. The build script runs tsc --declaration, producing dist/index.js as the entry point and dist/index.d.ts for the types, so consumers get type definitions while the shipped module stays CommonJS. That combination is deliberate for a library that has to work in Node, io.js and the browser.
The development tooling is unusually strict for a package this small. Tests run under jest with the ts-jest preset in a node environment, coverage is collected from the TypeScript sources excluding the test directory, and a coverageThreshold of 80 applies to lines, statements, branches and functions alike. Linting is wired to run automatically after the tests through the posttest script, with eslint using the shared eslint-config-braintree preset and prettier applied by the prebuild hook.
The commit workflow is just as opinionated. Husky runs on prepare to install the git hooks, commitlint enforces conventional commits, and commitizen with cz and cz-customizable provides the commit prompt. A .nvmrc pins the Node version for contributors. None of this affects the consumer, but it does say something about how the maintainers work, and for a package whose entire value is a correctly maintained table of brand patterns, that is relevant background rather than trivia.
MIT, and a major version ten that is still moving
The licence is MIT, and the package manifest declares the same, which keeps the library safe to vendor into a commercial checkout with almost no obligation beyond keeping the notice.
The release history is where a team should look before pinning. v10.3.0 was published on 2026-10-13 and v10.3.1 followed the same day, while the release before the major line, v10.0.2, dates from 2025-04-30. The last push to the repository was on 2026-10-13 and the repository is not archived.
The released versions in that window run from 10.0.2 to 10.3.0 and 10.3.1, so consumers pinning across that range should read the changelog before upgrading. There is a CHANGELOG.md in the repository, a CONTRIBUTING.md, a SECURITY.md for reporting problems and a.cz-config.js for the commit prompt.
The one thing the documentation does not do is explain how the pattern table is sourced or how often it is checked against the issuing banks. Each card type has a patterns attribute made of numbers and ranges, and the README describes how those are matched. If your business depends on recognising a specific regional brand, that is the question to ask the maintainers, because the library will not answer it for you.
Editorial conclusion
Adopt credit-card-type if you are building a card input that should adapt its formatting and its security code label as the user types, and if you would rather not maintain a brand pattern table yourself. Do not adopt it expecting validation: it does not check a checksum, and it returns an empty array for a number that matches nothing, so you still need a luhn check and your own rejection rules. Verify three things first: that you normalize the number before calling it, since the string must contain only integers, that the brand you expect is actually in the list of fifteen constants, and that your bundler handles the CommonJS output. The last push was on 2026-10-13 with v10.3.1 published the same day, and the previous v10.0.2 dates from 2025-04-30, so check the changelog across the major version before pinning.
Frequently asked questions
Does credit-card-type validate card numbers?
No. The README states that it is not a validation library but a smaller component to help you build your own validation or UI library. It determines the brand, the formatting gaps, the expected lengths and the security code name, and nothing more.
Can credit-card-type detect a brand while the user is still typing?
Yes, that is the stated design, type-as-you-go detection with support for partial numbers. The example in the README uses the four digits 4111 to get a Visa result.
What happens when several card brands share the same first digit?
The function returns an array, so you get every candidate. The README example shows that a single 6 matches six brands, starting with Discover, UnionPay and Maestro, and an empty array is returned when nothing matches.
How do I find the security code name and length for a brand?
Each result includes a code object with a name and a size, such as CVV with size 3 for Visa, CVC with size 3 for Mastercard and CID with size 4 for American Express. getTypeInfo returns the same object for a known type string.
How do I install and import credit-card-type?
Run npm install credit-card-type. The package is built from TypeScript sources into CommonJS with tsc --declaration, so it works with require as well as with named ES6 imports of getTypeInfo and types.
What licence is credit-card-type released under?
MIT, declared in the package manifest and stored in the LICENSE file at the root of the repository.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/braintree-credit-card-type)Was this useful?