String.prototype.codePointAt() returns the full Unicode code point starting at a UTF-16 index (same API as MDN String.prototype.codePointAt()). Learn emoji / surrogate pairs, out-of-range undefined, how it differs from charCodeAt(), safe looping, five examples, and try-it labs.
01
Kind
Instance method
02
Returns
Code point / undefined
03
Emoji
Full value
04
vs charCodeAt
UTF-16 unit only
05
Mutates?
No
06
Baseline
Widely available
Fundamentals
Introduction
Unicode code points run from 0 to 0x10FFFF (over one million). JavaScript strings store text as UTF-16 code units (0–65535). Characters above U+FFFF — including many emoji — use two units (a surrogate pair).
charCodeAt() always returns one unit. codePointAt() returns the full character value when you start at the leading surrogate — so "😍".codePointAt(0) is 128525, not a half-emoji number.
💡
Beginner tip
Indexes are still UTF-16 based (same as length). Out of range, codePointAt() returns undefined — not NaN.
codePointAt(index) reads the Unicode code point that starts at that UTF-16 index. If the unit there is a leading surrogate with a matching trail, you get the combined code point.
Indexes are zero-based UTF-16 positions — same as charAt.
Valid results are integers from 0 to 0x10FFFF.
Missing position — returns undefined.
A trailing-surrogate-only index returns just that unit (not the full emoji).
Foundation
📝 Syntax
General form of String.prototype.codePointAt:
JavaScript
str.codePointAt(index)
Parameters
index — zero-based UTF-16 position where the character starts. Converted to an integer (undefined becomes 0).
Return value
A number (the Unicode code point) or undefined. Special cases:
Situation
Returns
Valid BMP character (e.g. "A", "★")
Code point 0–65535 (e.g. "A".codePointAt(0) → 65)
Leading surrogate of a pair (e.g. emoji at index 0)
Full code point (may be > 65535, e.g. "😍".codePointAt(0) → 128525)
Trailing surrogate only (e.g. emoji at index 1)
That trailing unit alone (e.g. 56845) — not the full emoji
Check misses with === undefined (or optional chaining). Do not use Number.isNaN here — that is for charCodeAt.
Example 5 — Loop by Code Point (Not by Index)
MDN advice: avoid a plain for over length with emoji.
JavaScript
const str = "\ud83d\udc0e\ud83d\udc71\u2764"; // 🐎 + 👤 + ❤
// Prefer for...of or spread (iterate code points):
[...str].map((cp) => cp.codePointAt(0).toString(16));
// ["1f40e", "1f471", "2764"]
// Index loop visits trailing surrogates too — usually not what you want:
for (let i = 0; i < str.length; i++) {
// may log half-emoji units as well as full points
str.codePointAt(i).toString(16);
}
for...of and spread use the string iterator, which yields one complete code point at a time. Then codePointAt(0) on each piece is safe.
Applications
🚀 Common Use Cases
Emoji & rare characters — get the real Unicode value, not a surrogate.
Hex / U+ notation — codePointAt(0).toString(16) for docs and logs.
Round-trip with fromCodePoint — rebuild characters from numeric IDs.
Safe iteration — pair with for...of / [...str].
Validation — check ranges for allowed symbols or scripts.
Not for grapheme clusters — family emoji / skin tones may need Intl.Segmenter.
🧠 How codePointAt() Resolves an Index
1
Receive an index
Convert to an integer (undefined becomes 0).
Input
2
Check the range
Outside 0…length - 1 → undefined.
Bounds
3
Read the unit(s)
If a leading surrogate + trail, combine into one code point.
Decode
4
✅
Return the number
Full Unicode value, a single BMP unit, or a lone trail surrogate.
Important
📝 Notes
Indexes are UTF-16 code units, even though the return value is a code point.
Out-of-range indexes return undefined, not NaN.
Calling codePointAt() with no argument is the same as codePointAt(0).
Starting on a trailing surrogate returns only that unit — start on the leading one for the full emoji.
Prefer for...of / spread when iterating characters that may be emoji.
Visible “characters” with modifiers (ZWJ sequences) may span multiple code points — use a segmenter when needed.
Compatibility
Browser & Runtime Support
String.prototype.codePointAt() is Baseline Widely available — supported across modern browsers since 2015.
✓ Baseline · Widely available
String.codePointAt()
Safe for production. Prefer this over charCodeAt() whenever emoji or full Unicode values matter.
UniversalWidely available
Google ChromeSupported · Desktop & Mobile
Full support
Mozilla FirefoxSupported · Desktop & Mobile
Full support
Apple SafariSupported · macOS & iOS
Full support
Microsoft EdgeSupported · Chromium
Full support
Internet ExplorerNo native support · Use a polyfill
Polyfill
OperaSupported · Modern versions
Full support
Samsung InternetSupported · Android
Full support
BunSupported · JavaScript runtime
Supported
DenoSupported · JavaScript runtime
Supported
Node.jsSupported · Server runtime
Supported
Android WebViewSupported · Modern WebView
Full support
codePointAt()Excellent
Bottom line: Use String.codePointAt() for full Unicode code points. Remember out-of-range returns undefined, and iterate with for...of when strings may contain emoji.
Wrap Up
Conclusion
String.prototype.codePointAt() returns the full Unicode code point at a UTF-16 index — including values above 65535 for emoji — or undefined when the position is missing. Pair it with fromCodePoint() and iterate with for...of for reliable Unicode work.
Call it at the start of a character (leading surrogate)
❌ Don’t
Expect out-of-range results to be NaN
Assume every index is the start of a full character
Loop with i++ over length for emoji strings
Use fromCharCode for values above 65535
Forget that one visible emoji can still be several code points
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about String.codePointAt()
Full Unicode code points with undefined for missing indexes.
5
Core concepts
📝01
Returns
code point / undefined
API
😀02
Emoji
full value at 0
Unicode
❌03
Miss
undefined
Bounds
⚡04
Loop
for...of / spread
Pattern
📄05
Mutates
no
Immutable
❓ Frequently Asked Questions
String.prototype.codePointAt(index) returns a non-negative integer — the Unicode code point of the character starting at that UTF-16 index. Out of range, it returns undefined.
charCodeAt() always returns one UTF-16 code unit (0–65535). codePointAt() returns the full Unicode code point, which can be larger than 65535 when the character is a surrogate pair (many emoji).
undefined. That differs from charCodeAt(), which returns NaN, and from charAt(), which returns "".
Indexes are still UTF-16 code units (same as length and charAt). For a two-unit emoji, index 0 returns the full code point; index 1 lands on the trailing surrogate and returns only that unit.
Use String.fromCodePoint(codePoint). Prefer that over fromCharCode() when the value may be above 65535.
Prefer for...of or [...str] — they iterate by code point. Looping with for (i = 0; i < str.length; i++) visits both halves of a surrogate pair.
Did you know?
A single “character” on screen can be several Unicode code points — for example a family emoji joined with Zero Width Joiners. codePointAt reads one code point at a time; counting what a user sees may need Intl.Segmenter with granularity: "grapheme".