Word Counter
Count words, characters, sentences, and paragraphs in your text with our free online tool. Essential for writers, students, and content creators who need to meet specific word count requirements.
Word Count Statistics
| Metric | What It Counts |
|---|---|
| Words | Space-separated tokens |
| Characters | All characters including spaces |
| Characters (no spaces) | Letters, numbers, punctuation only |
| Sentences | Periods, question marks, exclamations |
| Paragraphs | Text blocks separated by line breaks |
Common Word Count Requirements
| Content Type | Typical Length |
|---|---|
| Tweet | 280 characters |
| Meta description | 150-160 characters |
| Blog post | 1,000-2,000 words |
| Essay | 500-5,000 words |
| Novel | 70,000-100,000 words |
Word Counter Implementation
``javascript
function countWords(text) {
const trimmed = text.trim();
if (!trimmed) return { words: 0, characters: 0, sentences: 0, paragraphs: 0 };
const words = trimmed.split(/\s+/).filter(w => w.length > 0).length;
const characters = trimmed.length;
const charactersNoSpaces = trimmed.replace(/\s/g, '').length;
const sentences = (trimmed.match(/[.!?]+/g) || []).length;
const paragraphs = trimmed.split(/\n\n+/).filter(p => p.trim().length > 0).length;
return { words, characters, charactersNoSpaces, sentences, paragraphs };
}
`
Reading Time Estimation
Average reading speeds vary by content complexity. Our tool estimates reading time based on 200-250 words per minute for average readers, helping you gauge how long your content takes to consume.
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.