Match a 6-digit OTP
Pull a 6-digit one-time password out of an SMS or email body using a word-boundary match, without grabbing part of a longer number.
Last updated
Matches
- Your OTP is 482913 today
- Reference code: 100200 expires soon
Doesn’t match
- 12345
- 1234567
- OTP is 12
Why it’s written this way
\d{6} is the core of it: exactly six digits, no more and no fewer. Wrapping it in \b...\b — word boundaries — stops it from matching the middle of a longer run of digits, like the '482913' buried inside a 10-digit phone number.
It's deliberately left unanchored: an OTP arrives inside a sentence ('Your code is 482913'), not as the entire string, so ^ and $ would never match real SMS or email text.
Edge cases to know
- →Any six-digit number matches — an order ID, a PIN, or a slice of a longer reference number triggers a false positive just as easily as a real OTP.
- →It can't tell a code apart from surrounding digits split by a non-word character, like '482-913' — that reads as two separate 3-digit runs, not one 6-digit code.
- →Extracting an OTP from message text is one thing; logging or storing what you extract is another — treat matched codes as sensitive and keep them out of logs and analytics.
Part by part
- \b
- Word boundaries so the six digits stand alone, rather than being pulled out of the middle of a longer number.
- \d{6}
- Exactly six digits. The fixed count is the whole pattern — anything more flexible stops being a code matcher.
Common mistakes
\d{6}Without boundaries the pattern finds six digits inside any longer number, so an order reference or a timestamp in the same message yields a false code — and it will look plausible.
\b\d{6}\b\b\d{4,8}\bA range accepts years, PINs and part numbers alongside codes. If you support several code lengths, list them as alternatives so each is deliberate rather than allowing everything in between.
^\d{6}$Anchoring is right for a form field and wrong for reading a code out of an SMS, where the digits sit inside a sentence. Copying the anchored form into a message parser makes it match nothing.
Questions
How do I extract a code from an SMS reliably?
Prefer the platform's own mechanism — the origin-bound one-time code format that browsers and mobile operating systems understand — and fall back to this pattern. Anchoring on nearby words such as "code" also cuts false positives sharply.
Should codes be compared as strings or numbers?
As strings, always. Parsing to a number destroys leading zeros, so 012345 becomes 12345 and fails to match a stored code that kept them. This is a genuinely common bug.
Does matching mean the code is valid?
No. It confirms the shape only — not that the code was issued, is unexpired, belongs to this user, or has not already been used. Every one of those checks belongs on the server.
Is six digits secure enough?
Only in combination with rate limiting and a short expiry. A million possibilities falls quickly to unlimited guessing, so the security comes from limiting attempts rather than from the length of the code.