
String Length Calculator
Characters, bytes (UTF-8/UTF-16/ASCII), codepoints, graphemes, URL-encoded length, and Base64 length - all at once.
Last reviewed: June 2026New to this tool? Click here for instructions
How to Use the String Length Calculator
Paste text into the input area and the metrics update instantly. Summary mode shows the headline counts, Encoding mode shows a per-character byte breakdown, and Compare mode helps explain why two strings that look similar can have different codepoints.
When to Use the Tool in Real Workflows
Use it when checking database field limits, API payload sizes, SMS or push-message limits, URL query length, Base64 expansion, Unicode normalization issues, or emoji-aware UI counters.
How It Works
The calculator runs in local browser JavaScript. It uses String.length for UTF-16 code units, TextEncoder for UTF-8 byte length, Array.from() for codepoints, Intl.Segmenter for grapheme clusters when available, and encodeURIComponent() for URL-encoded length. Your string is not uploaded to an external tool.
Useful references: MDN String.length, MDN TextEncoder, MDN Intl.Segmenter, and Unicode UAX #29 text segmentation.
Tips, Edge Cases, or Limitations
- JavaScript
.lengthcounts UTF-16 code units, so a single emoji can count as 2. - Grapheme count is usually the best user-facing character limit because it tracks visible characters more closely.
- Byte limits depend on encoding. UTF-8 and UTF-16 can produce very different sizes for the same text.
- Normalize text before strict storage validation when accents or combining marks are possible.
Frequently Asked Questions
Measure string length in characters, bytes, codepoints, and grapheme clusters β across UTF-8, UTF-16, and ASCII encodings β instantly in your browser. Whether you're validating database column limits, debugging an emoji-aware character counter, or investigating why Python and JavaScript disagree on a string's length, the six metrics this tool surfaces cover every angle a working developer needs.
What This Tool Does
Paste any text into the input and the tool immediately returns six distinct measurements: character count (JavaScript UTF-16 code units, matching String.prototype.length), UTF-8 byte count, UTF-16 byte count, grapheme cluster count (visible characters as a human would count them), Unicode codepoint count, and URL-encoded length (the output length of encodeURIComponent()). Each metric answers a different question β using JS .length to validate a database column limit, for instance, is a reliable path to production bugs. All computation runs via the browser's own TextEncoder, Intl.Segmenter, and encodeURIComponent APIs. No data leaves your machine.
π Privacy: This tool runs 100% in your browser. Your input is not uploaded, stored, or logged anywhere outside your local session.
How to Use It
Step-by-step instructions
- Paste or type your string into the input textarea above. Tab focus is supported; the tool updates on every keystroke.
- Read the metrics panel. Six cards update in real time β character count, UTF-8 bytes, UTF-16 bytes, grapheme clusters, codepoints, and URL-encoded length.
- Check the encoding breakdown table for a per-character view of how each codepoint contributes to the total byte cost.
- Copy any value with the copy button on its card, or download the full breakdown as JSON for use in scripts or documentation.
Worked example: 'Hello π (ΠΡΠΈΠ²Π΅Ρ)'
Click Try Example to auto-populate the exact string below, or type it manually.
Worked Example
- Input string
Hello π (ΠΡΠΈΠ²Π΅Ρ)
Step-by-step breakdown
- Paste the string or click Try Example. The sample mixes ASCII, one supplementary-plane emoji, spaces, punctuation, and six Cyrillic letters.
- JavaScript
.length: the ASCII letters, spaces, parentheses, and Cyrillic letters are one UTF-16 code unit each. The globe emoji is a surrogate pair and counts as two code units. Total: 17 UTF-16 code units. - UTF-8 byte count: ASCII letters and punctuation are one byte each, spaces are one byte each, the globe emoji is four bytes, and each Cyrillic letter is two bytes. Total: 25 UTF-8 bytes.
- UTF-16 byte count: 17 code units times 2 bytes per code unit equals 34 bytes.
- Codepoints and graphemes:
Array.from()counts 16 codepoints.Intl.Segmenteralso counts 16 grapheme clusters because this sample has no combining marks or ZWJ sequences. - URL-encoded length:
encodeURIComponent()leaves the ASCII letters and parentheses readable, converts spaces to%20, and percent-encodes every UTF-8 byte in the emoji and Cyrillic text. Total: 61 characters.
Expected output
| Metric | Value |
|---|---|
Character count (JS .length) | 17 |
| UTF-8 bytes | 25 |
| UTF-16 bytes | 34 |
| Grapheme clusters | 16 |
| Unicode codepoints | 16 |
| URL-encoded length | 61 |
Character Count vs. Byte Count vs. Codepoints
What a character count measures
In JavaScript, str.length returns the number of UTF-16 code units in the string β not visible characters, not codepoints. Characters in the Basic Multilingual Plane (U+0000βU+FFFF) occupy one code unit each; characters in supplementary planes (U+10000βU+10FFFF), which include most emoji and several rare scripts, occupy two code units via a surrogate pair. This is specified in ECMA-262 Β§6.1.4 and documented on MDN String.length. The practical consequence: a 10-emoji string can have .length === 20 while containing only 10 visible characters.
What a codepoint is
A Unicode codepoint is a numeric value in the range U+0000 to U+10FFFF, each assigned to a single abstract symbol in the Unicode Standard. Every letter, digit, punctuation mark, emoji, and control character gets exactly one codepoint. Python 3's len() counts codepoints, so len("π") == 1. JavaScript's .length counts UTF-16 code units, so "π".length === 2. Go's len() counts UTF-8 bytes, so len("π") == 4. Rust's .len() also counts UTF-8 bytes. The languages agree on almost nothing here, which is why cross-language string length bugs are so common. Use Array.from(str).length or [...str].length in JavaScript to get a codepoint count.
What a byte count measures
Byte counts are the right unit when your constraint is storage or network bandwidth rather than display. UTF-8 encodes each codepoint as 1β4 bytes depending on its value: the ASCII subset (U+0000βU+007F) stays at 1 byte per character, making UTF-8 optimal for English-heavy text. UTF-16 uses 2 bytes for every BMP codepoint and 4 bytes for supplementary ones. Use byte count for MySQL/PostgreSQL VARCHAR byte-length limits, HTTP Content-Length headers, and maximum message size checks in binary protocols. Use grapheme count for UI input fields where the limit is "characters a human can see." Use codepoint count when interfacing with APIs that document their quotas in Unicode characters β many NLP and translation APIs do this.
Why Emoji Have Unexpected Lengths
Surrogate pairs and supplementary codepoints
Emoji assigned codepoints above U+FFFF live in Unicode's supplementary planes. UTF-16 cannot encode these in a single 16-bit code unit, so it uses a surrogate pair: a high surrogate (U+D800βU+DBFF) followed by a low surrogate (U+DC00βU+DFFF). JavaScript strings are sequences of UTF-16 code units, so the earth globe emoji π (U+1F30D) gives "π".length === 2 even though it is a single codepoint. Its UTF-8 footprint is 4 bytes. Its grapheme count is 1. This is not a JavaScript bug β it is a direct consequence of the UTF-16 encoding model mandated by ECMA-262. Any character counter in a JavaScript application that uses raw .length for display-facing limits is broken for emoji input.
Emoji modifier sequences and ZWJ sequences
The complexity compounds with composed emoji. A thumbs-up with a medium skin tone β ππ½ β is two codepoints: U+1F44D (thumbs up) followed by U+1F3FD (medium skin tone modifier, one of the Fitzpatrick modifier range U+1F3FBβU+1F3FF). JavaScript reports .length === 4 while Intl.Segmenter reports 1 grapheme. The family emoji π¨βπ©βπ§ is more extreme still: three emoji joined by two Zero Width Joiner characters (U+200D), totalling 5 codepoints, .length === 8, and 18 UTF-8 bytes β yet the user sees exactly one character. Grapheme cluster boundary rules for these sequences are defined in Unicode Standard Annex #29 (UAX #29). Any Twitter/X-style character counter, SMS byte-length validator, or database truncation guard must use Intl.Segmenter (standardised in ECMAScript 2022) rather than .length to avoid off-by-one errors that only surface when users send emoji.
UTF-8, UTF-16, and ASCII Encoding Breakdowns
ASCII and single-byte range
ASCII is a strict 7-bit subset covering U+0000βU+007F (128 codepoints). Within this range, all three major encodings converge: UTF-8 uses 1 byte, UTF-16 uses 2 bytes, UTF-32 uses 4 bytes. UTF-8's 1-byte encoding for ASCII is why it dominates the web β most HTML, JSON, and source code is overwhelmingly ASCII, so UTF-8-encoded text is compact and backward-compatible with legacy ASCII readers. Once you leave the ASCII range, UTF-8 costs increase: U+0080βU+07FF (Latin Extended, Cyrillic, Greek, Arabic, Hebrew, and others) require 2 UTF-8 bytes; U+0800βU+FFFF (most CJK ideographs, various symbols) require 3 bytes; U+10000βU+10FFFF (supplementary planes, including most emoji) require 4 bytes. This is the encoding scheme specified in RFC 3629 Β§3.
Multi-byte scripts: Cyrillic, Arabic, CJK
A Cyrillic character like Π (U+041F) sits in the U+0080βU+07FF band: 2 UTF-8 bytes, 2 UTF-16 bytes. A full six-letter Cyrillic word like ΠΡΠΈΠ²Π΅Ρ costs 12 UTF-8 bytes and 12 UTF-16 bytes β identical, because all Cyrillic codepoints are BMP. A CJK ideograph like δΈ (U+4E2D) is in the U+0800βU+FFFF band: 3 UTF-8 bytes but only 2 UTF-16 bytes. For CJK-heavy content, UTF-16 is actually more compact than UTF-8. Arabic characters (U+0600βU+06FF) match the Cyrillic pattern: 2 UTF-8 bytes, 2 UTF-16 bytes each.
UTF-32 as baseline
UTF-32 assigns exactly 4 bytes to every codepoint, regardless of its value β the simplest encoding for indexed access (O(1) per codepoint) but the most space-hungry. A 10-character ASCII string takes 40 bytes in UTF-32 versus 10 in UTF-8. UTF-32 is rarely used for storage or transmission; its main utility is as a conceptual baseline for understanding why variable-width encodings exist.
| Character | Unicode Codepoint | ASCII bytes | UTF-8 bytes | UTF-16 bytes | UTF-32 bytes |
|---|---|---|---|---|---|
| C | U+0043 | 1 | 1 | 2 | 4 |
| a | U+0061 | 1 | 1 | 2 | 4 |
| f | U+0066 | 1 | 1 | 2 | 4 |
| Γ© | U+00E9 | β | 2 | 2 | 4 |
| (space) | U+0020 | 1 | 1 | 2 | 4 |
| β | U+2615 | β | 3 | 2 | 4 |
| Totals (6 chars) | 4 of 6 chars encodable | 9 | 12 | 24 |
| Script Family | UTF-8 bytes | UTF-16 bytes | UTF-32 bytes |
|---|---|---|---|
| Latin (ASCII) | 10 | 20 | 40 |
| Cyrillic | 20 | 20 | 40 |
| Arabic | 20 | 20 | 40 |
| CJK (Chinese) | 30 | 20 | 40 |
| Emoji (supplementary) | 40 | 40 | 40 |
Edge Cases: Combining Characters and Grapheme Clusters
Combining diacritics
The letter Γ© can exist in two Unicode representations that look identical on screen but have different lengths at every level below grapheme. NFC (Normalization Form Composed) stores it as a single precomposed codepoint U+00E9: 1 codepoint, 2 UTF-8 bytes, 1 JS .length unit. NFD (Normalization Form Decomposed) stores it as the base letter e (U+0065) followed by the combining acute accent U+0301: 2 codepoints, 3 UTF-8 bytes, .length === 2. Both forms yield exactly 1 grapheme cluster. Text copied from macOS tends toward NFC; some Linux text pipelines produce NFD. If your validation logic compares against a character limit using codepoint or byte counts, normalize first β otherwise the same visible string can pass or fail depending on where it was typed. Call String.prototype.normalize('NFC') before measuring when consistent byte counts matter.
Zero-width characters
Zero Width Joiner (U+200D), Zero Width Non-Joiner (U+200C), Zero Width Space (U+200B), Soft Hyphen (U+00AD), and Byte Order Mark (U+FEFF) are real codepoints that render invisibly but still increment JS .length, codepoint count, and byte counts. They appear frequently in text pasted from rich-text editors, Word documents, web scrapers, and internationalized content. A 20-character display string with embedded ZWJ characters can exceed a 20-byte database limit with no obvious explanation. This tool's grapheme counter reveals the discrepancy between what the user typed and what the validator rejects.
Normalization forms
Unicode Normalization Form C (NFC) and Form D (NFD) directly affect codepoint and byte counts for any string containing accented characters or symbols with decomposable forms. The Regex Tester on this site can help identify combining character sequences with the pattern \p{M}+ (Unicode category M = Mark). For length-sensitive code paths, always normalize before measuring β str.normalize('NFC').length gives the canonical shortest form. Grapheme count remains stable across normalization forms, which is another argument for using it as the user-facing limit metric.
| Metric | What It Counts | API / Method | Best Used For | Example: 'π' |
|---|---|---|---|---|
JS .length |
UTF-16 code units | str.length |
Low-level JS string operations | 2 |
| UTF-8 bytes | Bytes in UTF-8 encoding | new TextEncoder().encode(str).length |
DB column limits, HTTP Content-Length | 4 |
| UTF-16 bytes | Bytes in UTF-16 encoding | str.length * 2 |
Java/C# string memory size, Windows APIs | 4 |
| Unicode codepoints | Abstract Unicode characters | Array.from(str).length |
API quota limits, language-neutral counts | 1 |
| Grapheme clusters | Visually distinct characters | Intl.Segmenter |
UI character limits, user-facing counters | 1 |
| URL-encoded length | Characters after percent-encoding | encodeURIComponent(str).length |
Query string limits, URL max-length checks | 12 |
| String | JS .length |
Codepoints | Graphemes | UTF-8 bytes |
|---|---|---|---|---|
Hello (ASCII) | 5 | 5 | 5 | 5 |
β
(U+2605, BMP symbol) | 1 | 1 | 1 | 3 |
π (U+1F30D, earth globe) | 2 | 1 | 1 | 4 |
ππ½ (thumbs + skin modifier) | 4 | 2 | 1 | 8 |
π¨βπ©βπ§ (family, 2Γ ZWJ) | 8 | 5 | 1 | 18 |
cafΓ© (NFC, precomposed) | 4 | 4 | 4 | 5 |
.length and visible grapheme count. The family emoji row is the most extreme: .length === 8 for a single visible character.Behind the Scenes: Unicode and Encoding Standards
How the tool counts graphemes
Grapheme cluster segmentation follows the boundary rules in Unicode Standard Annex #29 (UAX #29, Unicode Text Segmentation). The tool invokes new Intl.Segmenter(undefined, { granularity: 'grapheme' }) and spreads the resulting iterator to count segments β the approach specified in the ECMAScript Internationalization API Specification. UTF-8 byte count is computed via the WHATWG Encoding Standard's TextEncoder API: new TextEncoder().encode(str).length. Codepoint count uses Array.from(str).length, which correctly splits surrogate pairs so each emoji codepoint counts as 1. URL-encoded length runs encodeURIComponent(str).length, which percent-encodes every non-ASCII byte as a %XX triplet per RFC 3986.
Spec references
ECMA-262 Β§6.1.4 defines the JavaScript string type as a sequence of UTF-16 code units and specifies that .length returns the number of code units. RFC 3629 Β§3 defines the UTF-8 byte encoding table used to determine per-codepoint byte costs. UAX #29 defines the grapheme cluster boundary algorithm. The Unicode FAQ on combining characters provides further reading on why "character" is an ambiguous term and recommends specifying grapheme, codepoint, or code unit depending on context.