The sentence "Count tokens before you pay for them." split into its eight o200k_base tokens, each with its numeric id and a note on why the split lands there.
Eight tokens for seven words and a full stop. Every word carries its leading space into the token, which is why " tokens" and "tokens" are different ids, and why the first word of a text is often tokenized differently from the same word mid-sentence. The ids are ranks in the merge table, so small numbers are the most frequent pieces of English.

Every model bill is a token count times a price, and the token count is the only half you can change before sending. The counter above uses the same byte-pair vocabularies the OpenAI API uses, so its numbers are the billed numbers for GPT-5, GPT-4.1, GPT-4o, GPT-4 and GPT-3.5, not a characters-divided-by-four guess. For Claude it says "estimate", because nothing else would be honest.

1,000 English words: 1,358 tokens in o200k_base·a random UUID: 20 to 26 tokens for 36 characters·pretty JSON minified: 36 % fewer tokens, measured·Claude: estimates, tokenizer unpublished

What a token is, and why "4 characters" fails

A token is an entry in the model's vocabulary, and the vocabulary was built by byte-pair encoding. Start with the 256 byte values, scan a large corpus, merge the most frequent adjacent pair into a new entry, repeat until the table has the target size. o200k_base stopped at about 200,000 entries, cl100k_base at about 100,000, p50k_base at about 50,000. Frequent English words and word pieces got their own entries early (" the", " support", "ization"), rare strings never did and fall back to shorter pieces, in the worst case single bytes.

Encoding runs the merges in reverse. A regular expression first cuts the text into pre-tokens (a word with its leading space, a run of digits up to three long, a run of punctuation, a run of whitespace), then each pre-token is merged greedily from the rank table. That is why " tokens" with its leading space is one token, why "hello world" is two tokens and "HELLO WORLD" three, why a number splits every three digits, and why the same word can cost differently depending on what stands before it.

$ node -e "const {countTokens,encode}=require('gpt-tokenizer/encoding/o200k_base');for(const s of ['Count tokens before you pay for them.','{\"ok\": true}','日本語のテキスト','😀'])console.log(countTokens(s),JSON.stringify(encode(s)),JSON.stringify(s))"
8 [3417,20290,2254,481,2777,395,1373,13] "Count tokens before you pay for them."
5 [10848,525,1243,1343,92] "{\"ok\": true}"
6 [9048,40909,3385,16056,18368,38236] "日本語のテキスト"
1 [84083] "😀"
node 22.22.3 · gpt-tokenizer 4.0.0 · macos 26.6.1

The "one token is about four characters" rule is correct for exactly one kind of text. Our cron parser article, 10,979 characters of English prose, encodes to 2,748 tokens, 4.00 characters per token. Everything else misses. The German sample runs 5.1 characters per token but 1.45 tokens per word instead of 1.36, TypeScript source 3.8 characters per token and 2 tokens per word, pretty-printed JSON 2.6 characters per token, the Japanese sample 1.6, a random UUID about 1.6 as well with a worst case near 1. A budget built on the four-character rule is 36 percent short on the JSON and 61 percent short on the Japanese text.

Which tokenizer counts for which model

Three OpenAI vocabularies cover every model people still call, and the right one is a function of the model, not of the text.

VocabularyEntries (gpt-tokenizer 4.0.0)Models
o200k_base200,006GPT-5 family, GPT-4.1 family, GPT-4o and GPT-4o mini, o1, o3, o4-mini
cl100k_base100,264GPT-4, GPT-4 Turbo, GPT-3.5 Turbo, text-embedding-ada-002, text-embedding-3
p50k_base50,281text-davinci-002 and -003, code-davinci-002 (the original Codex)
r50k_base50,257GPT-3 davinci, GPT-2

The counter above loads the first three on demand, which is the honest way to do it. o200k_base is 2.4 MB of merge ranks, cl100k_base 1.2 MB, p50k_base 0.6 MB, and downloading all of them for a visitor who wants one number would be rude. Each one is fetched once when you pick it and stays cached in the tab.

Everyone else has their own vocabulary. Anthropic published a tokenizer for Claude 2 and has not for Claude 3 onward, and Opus 4.7 switched to a new one that Anthropic's docs put at about 30 percent more tokens for the same text. The only exact count is the count_tokens endpoint, which is free, takes the same messages, system prompt and tool definitions as the real call, and never leaves the server. Gemini answers through countTokens, Google's Python SDK can also count locally, and Google's own guidance is 100 tokens for 60 to 80 English words. Llama 3 went the other way and adopted a tiktoken-style 128k vocabulary, Llama 2 still has a 32k SentencePiece one. Same text, five different numbers, and the differences are not noise. Vocabulary size is the main reason. A 200k vocabulary holds a merge for " Datenschutz" that a 50k vocabulary has to assemble from four pieces, which is why the German sample costs 77 tokens in o200k_base and 152 in p50k_base while English barely moves (1,358 against 1,325 per 1,000 words). For the Claude rows in the cost table the counter scales the o200k_base count by 1.3 for Opus 5 and Sonnet 5, the ratio of Anthropic's own words-per-token figure (about 555,000 words per million tokens) to o200k_base's (about 735,000), and leaves Haiku 4.5 at the plain count. For code, JSON and non-English text the gap goes either way, so treat those rows as a budget, not a bill, and confirm with the endpoint before committing to a number.

A table comparing token counts for an English sentence, a German sentence, a Japanese sentence, pretty and minified JSON, a JavaScript function, four emoji and a UUID in o200k_base and cl100k_base, with characters per token.
The four-characters-per-token rule holds for the English row and nothing else. Japanese runs at one character per token, a UUID at about 1.6 (hand-made ones that alternate letters and digits drop to 1.0), JSON at two and a half, and the newer o200k_base vocabulary is only noticeably cheaper than cl100k_base on non-English text and emoji. Characters are counted as code points, so the four emoji are nine.

Cutting tokens, measured

Advice about token reduction is usually unmeasured. These numbers are from the counter above, o200k_base, on texts you can paste yourself.

ChangeBeforeAfterSaved
order record, pretty JSON (2 spaces) to minified21914036 %
the same record, 4-space indent instead of 22192190 %
the same record, tabs instead of spaces219240−10 %
package.json of this site, pretty to minified56546618 %
12.6 KB TypeScript file, indentation stripped3,3463,1954.5 %
the "support prompt + JSON" sample, JSON block minified17511932 % of the block

Two things fall out of that table. Indent width is irrelevant, because a run of spaces is one token however long it is, so reformatting from four spaces to two saves nothing and the person who suggested it was guessing. And minifying JSON is the single cheapest cut there is, a third of the payload for zero change in meaning and one JSON.stringify without the indent argument, or a pass through the JSON minifier. The findings panel measures this for whatever JSON it finds inside your prompt, because "would save about a third" is an estimate and "would save 56 tokens" is a number you can act on.

The rest of the list, in order of how often it pays off. Replace identifiers the model only has to pass through. A random UUID is 20 to 26 tokens, id1 is one, and a lookup table on your side costs nothing. The SQL anonymizer and the code anonymizers next to it do exactly that for a whole query or file, table_1 and col_2 in place of every name of yours, with the lookup table kept as a key in your browser. Send files as files, because a Base64 image in the prompt costs about two thirds of a token per character and the model cannot decode it anyway, every provider has an image or file input for this. Strip boilerplate that arrives with copied text, including the invisible characters this page counts separately, because a zero-width space is a full token and a PDF paste can carry hundreds. Shorten the system prompt once and save on every call for the rest of the product's life. Summarise the history instead of resending it whole, which is the next section.

What counts toward the bill

Everything in the request, every time. The API is stateless, so the system prompt, the tool definitions and the full conversation history are sent, tokenized and billed on every turn, not once. A 1,200-token system prompt in a 20-turn conversation is 24,000 billed input tokens before the user has said anything new, and a chat with a growing history is quadratic, since turn 20 resends turns 1 through 19.

On top of the text, the chat format adds framing. OpenAI's cookbook formula is 3 tokens per message plus 3 for the reply, small per message and not small across a history of 40. Tool definitions are JSON schemas serialised into the prompt, and a verbose schema with long descriptions is the silent cost centre in most agent setups. Images are tokenized by tile size rather than bytes, so a screenshot is hundreds of tokens regardless of what is on it.

Output is priced separately and higher, four to eight times per token in the table above. The prompt above is the cheap half of a call with a long answer, and the single most effective cost control is a tighter max_tokens plus an instruction on length. Prompt caching cuts the other half. OpenAI bills cached input at 10 to 50 percent of the list price depending on the model (a tenth on GPT-5), Anthropic bills cache reads at a tenth and cache writes at 1.25 times, which turns the 24,000 repeated tokens from the first paragraph into the price of 2,400 on GPT-5. The cache only hits if the prefix is byte-identical, so put the stable parts first and the changing parts last.

Context windows, and why fits is not works

The context fit panel says whether the prompt goes through the door. 8k, 32k, 128k, 200k and 1M are the sizes that models are still sold under, and going over any of them is a hard error rather than a truncation. The panel measures the prompt alone. Real requests add history, tools and the answer, and the answer needs room of its own, so a prompt at 90 percent of the window is already a problem.

Filling the window is a separate question from it working. Long-context evaluations keep finding the same shape. A model that retrieves a fact perfectly from a short context starts missing it in a long one, and is worst when the fact sits in the middle (the "lost in the middle" result from 2023, reproduced since on newer models and in the RULER benchmark, which found the usable context of many models well below the advertised size). A 1M window is a capacity, not a promise. For anything that has to be reliable, shorter prompts with the relevant material near the start or the end beat a full window every time, and they are cheaper by exactly the tokens you left out.

Counting tokens in code

For OpenAI models the reference is tiktoken, the same library the API uses. tiktoken.encoding_for_model("gpt-4o") resolves the vocabulary from the model name, tiktoken.get_encoding("o200k_base") picks it directly, and len(enc.encode(text)) is the count. In JavaScript, js-tiktoken and gpt-tokenizer (the one bundled here) ship the same ranks, so their numbers match to the token, and the repro block above is the three-line version. Note that encode in both raises on special tokens like <|endoftext|> unless told otherwise, which is why pasted transcripts sometimes crash naive counters. The counter on this page encodes them as plain text, the way the API would receive them.

For Claude, client.messages.count_tokens(model=..., system=..., messages=..., tools=...) in the Python and TypeScript SDKs, or the raw POST /v1/messages/count_tokens. It is free, rate-limited separately from messages, and counts the request exactly as it will be billed. For Gemini, client.models.count_tokens(model=..., contents=...) in the google-genai SDK. In all three cases the usage field of a real response is the authoritative number after the fact, and logging it per call is how you find out which feature is eating the budget.

One parameter name causes more confusion than the rest together. max_tokens (OpenAI now calls it max_completion_tokens) limits the answer, not the request. The request limit is the context window, and input plus output together must fit in it. So a 120,000-token prompt to a 128k model with max_tokens: 16000 fails, a 120,000-token prompt with max_tokens: 4000 goes through, and a short prompt with max_tokens: 50 comes back cut off mid-sentence with finish_reason: "length" rather than with an error.

The verdict, and when it is wrong

Use o200k_base for every current OpenAI model and for any estimate where the exact tokenizer is unavailable. cl100k_base only for GPT-4, GPT-3.5 Turbo and the embedding models, p50k_base for nothing new.

The estimate is weakest for Claude on code-heavy or non-English prompts, where the vocabularies diverge by far more than the 1.3 factor covers. Call count_tokens before you budget there.

Tokens, counted and paid for

How many tokens is a word?

About 1.3 to 1.4 tokens per English word in o200k_base and cl100k_base. Common short words are one token, a word like "tokenization" is two, "antidisestablishmentarianism" is six.

How many tokens are 1000 words?

Roughly 1,350 for English prose. Measured on the 2,023 words of our cron parser article: 1,358 tokens per 1,000 words in o200k_base, 1,357 in cl100k_base, 1,325 in p50k_base. German business prose runs about 1,450 per 1,000 words in o200k_base and 2,900 in p50k_base (the German sample above, 53 words, 77 and 152 tokens), and TypeScript source about 2,000, because punctuation and brackets are words to a tokenizer.

How many words is 100k tokens?

About 74,000 English words at the measured 1.36 tokens per word, roughly a 300-page book. The usual shortcut says 75,000.

How do I count tokens in Python?

pip install tiktoken, then len(tiktoken.get_encoding("o200k_base").encode(text)) for GPT-5, GPT-4.1 and GPT-4o, or tiktoken.encoding_for_model("gpt-4o") to resolve the vocabulary from the model name. For chat calls, add the per-message framing, which in OpenAI's cookbook formula is 3 tokens per message plus 3 for the reply, and the usage object in every API response gives the billed number exactly. For Claude, use client.messages.count_tokens() from the anthropic package, which calls the free count_tokens endpoint with the same messages, system prompt and tools you are about to send.

How do I count tokens for Claude?

Call the count_tokens endpoint: POST /v1/messages/count_tokens with the same model, system, messages and tools as the real request, or client.messages.count_tokens(...) in the official SDKs. It is free and does not run the model. Anthropic has not published a Claude tokenizer since Claude 2, so no offline library gives the exact number, and the tokenizer changed again with Opus 4.7, which Anthropic says produces about 30 percent more tokens than before. A tiktoken count with o200k_base times 1.3 is a usable English estimate for Opus 5 and Sonnet 5, the plain count for Haiku 4.5, and both drift further on code and non-English text.

Does whitespace count as tokens?

Yes, but cheaply in the newer vocabularies. A run of 40 spaces is one token in o200k_base and cl100k_base, and so is a run of 10 newlines, while p50k_base needs five tokens for the same 10 newlines. What adds up is not the run but the line. Every indented line of a pretty-printed file costs a newline token and an indentation token, 2 to 3 tokens per line in our measurements, so a 15-line JSON object pays 30 to 45 tokens for formatting alone. Indent width barely matters, and tabs cost slightly more than spaces in our measurement (240 versus 219 tokens for the same object).

Why is JSON so expensive in tokens?

Because almost every character of structure is its own token: quotes, colons, commas, braces, and a newline plus an indentation run per line. A 561-character pretty-printed order record measured 219 tokens in o200k_base, 2.6 characters per token against 4 for English prose. Minified, the same record is 381 characters and 140 tokens, 36 percent less, and the model reads it exactly as well. Numbers and ids make it worse still: a random UUID is 20 to 26 tokens, a 16-digit order number 6.

What is tiktoken?

OpenAI's open-source BPE tokenizer library for Python, with the vocabularies (o200k_base, cl100k_base, p50k_base, r50k_base) its models use. The JavaScript ports js-tiktoken and gpt-tokenizer ship the same ranks, which is how a token count in a browser can match the API.

Are input and output tokens priced the same?

No. Output tokens cost four to eight times more: GPT-5 lists $1.25 per million input tokens and $10 per million output, Claude Sonnet 5 $2 and $10, GPT-4o mini $0.15 and $0.60. A call with a 2,000-token prompt and a 500-token answer on GPT-5 therefore pays $0.0025 for the prompt and $0.005 for the answer. Long answers, not long prompts, are usually the bigger line on the bill, which is why max_tokens and "answer in under 100 words" are cost controls.

How many tokens in a page of text?

A page of about 500 English words is around 680 tokens in o200k_base. A dense A4 page of 600 words is closer to 800.

What is a context window?

The maximum number of tokens a model can take in one request, input and output together: system prompt, conversation history, tool definitions, attached documents and the answer being generated. 128k for GPT-4o, 200k for Claude Haiku 4.5 and o3, about 1M for GPT-4.1, Gemini 2.5 Pro, Claude Opus 5 and Sonnet 5. Exceeding it is a hard error ("prompt is too long", "maximum context length"), and filling it is not free either, since prices are per token and retrieval accuracy drops long before the window is full, with information in the middle of a long context the first casualty.

Do emojis count as tokens?

Yes, and unevenly: 😀 is 1 token in o200k_base and 2 in cl100k_base, 🚀 is 2 and 3, the flag 🇦🇹 is 4 and 6, and the family 👨‍👩‍👧 is 8 and 13, because it is three emoji joined by invisible joiners that cost tokens of their own.

Is it safe to paste a prompt into an online token counter?

Only if the counting happens in your browser. Prompts are the most sensitive text developers paste anywhere, because they carry system instructions, customer records, API responses and sometimes keys. Many online counters send the text to a server to tokenize it, and few say so. Here the vocabulary is downloaded once into the tab and the text is encoded locally, nothing is sent, and it keeps working with the network off.