String Byte Counter for UTF-8, UTF-16 and UTF-32
"How long is this string?" has at least four correct answers, and picking the wrong one leads to truncated database values, rejected API payloads and broken SMS messages. This string byte counter shows them side by side: the storage size in UTF-8, UTF-16, UTF-32 and Latin-1, the number of visible characters, Unicode code points and JavaScript code units, and the size after Base64 or URL encoding.
Why bytes and characters differ
Text is stored as numbers called code points, and an encoding decides how many bytes each one takes:
| Text | UTF-8 | UTF-16 | UTF-32 |
|---|---|---|---|
ASCII letter A | 1 byte | 2 bytes | 4 bytes |
Accented Γ© | 2 bytes | 2 bytes | 4 bytes |
Chinese δΈ | 3 bytes | 2 bytes | 4 bytes |
Emoji β (U+2615) | 3 bytes | 2 bytes | 4 bytes |
Emoji π (U+1F44B) | 4 bytes | 4 bytes | 4 bytes |
On top of that, one visible character (a grapheme) can be several code points. A waving hand with a skin tone is two code points, and a family emoji can be seven. So the character count you see, the code point count, and JavaScript's .length, which counts UTF-16 code units, often disagree.
Example
For the text Hello, δΈη! CafΓ© β ππ½ the tool reports:
UTF-8: 33 B
UTF-16: 44 B
UTF-32: 80 B
Latin-1: not representable (characters above U+00FF)
Characters (graphemes, what you see): 19
Unicode code points: 20
UTF-16 code units (JavaScript .length): 22
Non-ASCII code points: 6 (2 outside the BMP, e.g. emoji)
Words: 5 Β· Lines: 1
As Base64: 44 B
URL-encoded: 81 B
Nineteen visible characters take 33 bytes in UTF-8, while .length says 22. The URL-encoded form is more than twice the UTF-8 size, because every non-ASCII byte becomes a three-character %XX escape.
What each number is for
- UTF-8 bytes: the size on disk, in HTTP bodies, in most databases and in
Content-Length. This is the number to use for byte limits. - UTF-16 bytes and code units: memory use in JavaScript, Java and .NET strings, and the unit behind
String.length. The UTF-16 figure excludes a byte order mark. - UTF-32: a fixed four bytes per code point, useful as a worst-case estimate.
- Latin-1: shown only when every character is at or below U+00FF, as in legacy systems that store one byte per character.
- Graphemes: what a person would count, and the right number for user-facing limits.
- Base64 size: always four characters for every three bytes, about a third larger than the UTF-8 size.
Common limits checked for you
The report ends with a quick pass or fail against limits developers hit often: a 280-character post, a single SMS part (160 characters for plain GSM-7 text, 70 once any Unicode character appears), a MySQL VARCHAR(255), a roughly 160-character meta description, a 63-byte DNS label and a 4 KB cookie. The tweet check counts graphemes, while X weights some characters such as emoji differently, so treat it as an estimate. The SMS check treats only printable ASCII as GSM-7, which is slightly stricter than the real alphabet.
Common pitfalls
- MySQL
utf8is not full UTF-8. It stores up to three bytes per character, so four-byte emoji fail. Useutf8mb4. - Truncating by bytes can split a character. Cutting a UTF-8 string at byte 100 may leave half a multi-byte sequence. Truncate by code points or graphemes, then check the byte size.
- Invisible characters count. Zero-width joiners and non-breaking spaces add bytes you cannot see.
To see the actual bytes, run the text through UTF-8 encode, or compare the encoded forms with Base64 encode and URL encode. For word and sentence counts aimed at writers, use the word counter.
Privacy
Counting happens in your browser with the standard TextEncoder and Intl.Segmenter APIs. Your text is never sent to a server.