Character Counter
Count characters with and without spaces in your text. Essential for social media posts, SMS messages, meta descriptions, and any content with character limits.
Character Limits by Platform
| Platform | Character Limit |
|---|---|
| Twitter/X | 280 characters |
| Instagram caption | 2,200 characters |
| Facebook post | 63,206 characters |
| LinkedIn post | 3,000 characters |
| YouTube title | 100 characters |
| Meta description | 155-160 characters |
| SMS message | 160 characters |
Character Counting Methods
| Method | Includes |
|---|---|
| With spaces | All characters including whitespace |
| Without spaces | Only letters, numbers, punctuation |
| Letters only | Alphabetic characters only |
| Alphanumeric | Letters and numbers only |
Character Counter Implementation
``javascript
function countCharacters(text) {
return {
total: text.length,
withoutSpaces: text.replace(/\s/g, '').length,
letters: (text.match(/[a-zA-Z]/g) || []).length,
numbers: (text.match(/[0-9]/g) || []).length,
punctuation: (text.match(/[^\w\s]/g) || []).length,
spaces: (text.match(/\s/g) || []).length
};
}
`
Unicode and Special Characters
Unicode characters like emojis may count as multiple characters in some systems. Twitter counts most emojis as 2 characters. Our tool shows both standard and Unicode-aware counts.
Counting Is Less Obvious Than It Looks
Two tools that both "count text" can disagree by a wide margin, because there is no single
definition of either a word or a character.
Words. Splitting on whitespace treats "state-of-the-art" as one word and "don't" as one;
splitting on non-letters gives four and two. Word processors differ from each other, and none
of them is wrong — they answer different questions.
Characters. Three different numbers are all defensible:
| Measure | "café 👨👩👧" |
|---|---|
UTF-16 code units (.length) | 13 |
| Unicode code points | 11 |
| Grapheme clusters (what a reader sees) | 6 |
The family emoji is a single visible character made of three people joined by zero-width
joiners — seven code points, one grapheme. This is why "👨👩👧".length returns 8 and why
truncating a string by .length can split an emoji in half.`javascript
const graphemes = [...new Intl.Segmenter('en', { granularity: 'grapheme' })
.segment(text)].length;
`
Limits Worth Knowing
| Context | Limit | Counted as |
|---|---|---|
| X / Twitter post | 280 | Weighted — CJK counts double, links count as 23 |
| SMS | 160 | GSM-7 characters; any emoji switches to UCS-2 and drops it to 70 |
| Meta description | ~160 | Pixels, not characters — Google truncates by width |
| Title tag | ~60 | Also pixel-based |
| LinkedIn post | 3,000 | Characters |
Reading Time
The standard estimate is 200–250 words per minute for adult silent reading of general prose.
Technical material runs slower — 150–200 — and a page with code samples slower still, since
readers stop and parse rather than scan.
Encoding Is Not Encryption
Base64 and percent-encoding both make data safe to *transport*. Neither makes it secret —
both are trivially reversible by design, with no key involved. A Base64 string in a URL, a
cookie or a header is readable by anyone who sees it.
| Purpose | Use |
|---|---|
| Safe transport of binary over text | Base64 |
| Safe transport of text in a URL | Percent-encoding |
| Confidentiality | AES-GCM, TLS |
| Integrity | HMAC, a digital signature |
| Password storage | bcrypt, scrypt, Argon2 |
Size Costs
Base64 expands data by exactly 4/3 — three bytes become four characters — plus padding. A
100 KB image becomes about 133 KB as a data URI, and it cannot be cached separately from the
document that carries it. Inline small icons; link everything else.
Percent-encoding expands unpredictably: an ASCII character that needs escaping becomes three
characters, and a non-ASCII character becomes three per UTF-8 byte. é is %C3%A9 — six
characters for one letter.
UTF-8 Is the Only Sane Default
Every encoding decision on the modern web assumes UTF-8. Where it goes wrong:
btoathrows on non-Latin-1 input.Encode to UTF-8 bytes first:
btoa(String.fromCharCode(...new TextEncoder().encode(text))).
atobreturns Latin-1.Decode back withnew TextDecoder().decode(bytes).- A BOM breaks parsers. Excel writes one at the start of CSV exports; strip it before
parsing.
Length is ambiguous."👨👩👧".lengthis 8 in JavaScript, 1 to a reader. Use
Intl.Segmenter` when the count is shown to a person.