Claude Token Counter: Count Tokens Exactly With the count_tokens API (and Budget Twitter (X) Data)

- Exact counter:
POST https://api.anthropic.com/v1/messages/count_tokens, orclient.messages.count_tokens()in Python; the response is{"input_tokens": N}. - Free, separate limit: counting costs nothing and has its own RPM cap (5,000 / 10,000 / 20,000 by usage tier), independent of message creation.
- What it counts: system prompt, tools, messages, base64 images and PDFs, prior thinking blocks; it rejects most server tools, the MCP connector and
url/filesources. - Model-specific: Claude 4.7 and later use a newer tokenizer that yields about 30 percent more tokens for the same text; tiktoken is OpenAI's tokenizer, not Claude's.
- Tweets as input (study, collected in 2026): median tweet text 192.5 characters; a raw API tweet object is a median 23.4x longer than a trimmed line.
- Budget formula: tokens / 1,000,000 x input $ per MTok; an estimated 116,311 tokens per 1,000 trimmed tweets is about $0.23 on Sonnet 5.5 (estimate, not a measured count).
Search for a Claude token counter and you get two kinds of answer: browser widgets that guess, and Anthropic's own endpoint that counts. This page is about the second one: how to call it, what it does and does not count, why the number moves between Claude models, and how to turn it into a dollar figure before you send a request.
It is written for builders who feed real data to Claude, so it ends with a measured example: we pulled 1,640 recent posts from twelve organization accounts and looked at how much text a tweet really is, and how much larger the raw API object is than the words you care about. For the full Claude price table and a per-1,000-tweet cost breakdown by model, see our Claude API pricing guide; for getting a key, the Claude API key guide. This page stays on counting.
23.4x more characters per post (median) across 1,640 posts from 12 organization accounts, collected in 2026. Trim tweets before you run count_tokens or pay for input.
What is the Claude token counter?
Anthropic ships an official token counting endpoint in the Messages API: POST https://api.anthropic.com/v1/messages/count_tokens. Anthropic's docs describe it as a way to "determine the number of tokens in a message before you send it to Claude", and list three uses: managing rate limits and costs, making model routing decisions, and fitting a prompt to a target length.
The request body is the same structured input you would send to https://api.anthropic.com/v1/messages: a model, an optional system prompt, the messages array, and optionally tools and thinking settings. The response has one field, input_tokens. There is no output count, because output tokens do not exist until Claude writes them.
It is an estimate, a precise one. The docs say "the actual number of input tokens used when creating a message might differ by a small amount." They also note that the count can include tokens Anthropic adds automatically for system optimizations, and that you are not billed for those system-added tokens. Billing reflects only your content.
It is model-specific. The endpoint counts under the tokenizer of the model you pass. Pass the exact model ID you will use for inference, not a cheaper sibling, or the number will not match your bill.
It is on every platform Anthropic lists. The token counting page marks the feature stable on the Claude API, Amazon Bedrock, Claude Platform on AWS, Claude models on Google Cloud and Microsoft Foundry, and says all active models support it. It is not available inside Managed Agents.
How to count Claude tokens with the API (cURL and Python)
You need an Anthropic API key (see our Claude API key guide). The cURL example below is Anthropic's own documentation example; it returns {"input_tokens": 14} for a two-word user message plus a short system prompt.
In Python, the official anthropic SDK exposes the same endpoint as client.messages.count_tokens(). In TypeScript it is client.messages.countTokens(). Anthropic's command-line tool has ant messages count-tokens with --model, --system and --message flags. All three call the same endpoint, so the count is identical.
Count the whole request, not just the user text. The quickest way to get a wrong budget is to count only the question. A long system prompt, a dozen tool schemas and a conversation history usually outweigh the new user turn. Build the request object once, pass it to count_tokens, then pass the very same object to messages.create.
Read the billed number afterwards. The usage.input_tokens field on the real Messages response is what you pay for. Log both numbers for a while; if they drift apart by more than a few tokens, something in your request differs between the two calls (a timestamp in the system prompt is the usual cause).
curl https://api.anthropic.com/v1/messages/count_tokens \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "content-type: application/json" \
-H "anthropic-version: 2026-10-21" \
-d '{
"model": "claude-opus-5-5",
"system": "You are a scientist",
"messages": [{"role": "user", "content": "Hello, Claude"}]
}'
# -> {"input_tokens": 14}
# Python SDK equivalent:
# import anthropic
#
# client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
#
# resp = client.messages.count_tokens(
# model="claude-sonnet-5-5",
# system="You summarize tweets for a newsletter.",
# messages=[{"role": "user", "content": open("prompt.txt").read()}],
# )
# print(resp.input_tokens)What does count_tokens count? System prompts, tools, images, PDFs and thinking
Anthropic's docs list what the endpoint accepts and what it rejects. The table below summarizes them; everything in it comes from the token counting page and the pricing page.
Tools carry a hidden system prompt. Anthropic's pricing page explains that when you send tools, the API adds a tool-use system prompt whose size depends on the model and on tool_choice. The table there lists 286 tokens for Claude Opus 5.5 and Claude Sonnet 5.5 with tool_choice auto or none, versus 675 for Claude Opus 4.7. That is on top of your own tool definitions, and count_tokens includes it, which is a good reason to count with tools attached rather than adding numbers by hand.
Server tools and MCP are counted after the fact. For requests that use server tools or the MCP connector, the docs point you to the usage object on the real Messages response. Server tools can also carry their own usage-based charges (the pricing page gives web search as an example), which no token count will show.
Prompt caching is ignored. The docs' FAQ says token counting "provides an estimate without using caching logic"; you may include cache_control blocks, but caching only happens on real message creation. So count_tokens tells you how big the prompt is, not how much of it will be billed at the cache-read rate.
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "search_tweets",
"description": "Search recent tweets by keyword and return text plus counts.",
"input_schema": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
}]
with_tools = client.messages.count_tokens(
model="claude-opus-5-5",
tools=tools,
messages=[{"role": "user", "content": "What are people saying about Claude Code?"}],
).input_tokens
without_tools = client.messages.count_tokens(
model="claude-opus-5-5",
messages=[{"role": "user", "content": "What are people saying about Claude Code?"}],
).input_tokens
print("tool definitions cost", with_tools - without_tools, "input tokens per request")Is the Claude token counter free? Pricing and rate limits
Yes. Anthropic's token counting page states that token counting "is free to use but subject to requests per minute rate limits based on your usage tier." The published limits are below; the docs add that counting and message creation have separate, independent limits, so counting every request before you send it does not eat into your Messages quota.
Higher limits are requested from the Rate limits page of the Claude Console (the docs call the button Request tier increase).
Free does not mean zero latency. Each count is a network round trip. For a chat app that counts every turn, that is one extra request per turn. A common pattern is to count only when a conversation is likely to approach a limit (for example, once a running estimate passes half the context window), or to count a template once and add the variable part.
Why tiktoken and character rules only approximate Claude tokens, and why models differ
Several browser-based "Claude token counter" pages in today's search results label their numbers as estimates. A tokenizer often used for such estimates, tiktoken, describes itself in its own README as "a fast BPE tokeniser for use with OpenAI's models". It encodes text the way OpenAI's models do, so applying it to Claude gives a different number. Anthropic's docs point to the count_tokens endpoint, called with the model you plan to use, as the way to get exact counts.
Anthropic's glossary gives the only official rule of thumb: on models before Claude 4.7 a token represents approximately 3.5 English characters, and Claude 4.7 and later models (and Claude Mythos Preview) use a newer tokenizer that produces approximately 30 percent more tokens for the same text. The glossary also says the characters per token depend on the model and the language, and tells you to use token counting for exact numbers.
Use the rule for budgeting, never for limits. A ratio is fine for a back-of-the-envelope estimate of a monthly bill. It is not fine for deciding whether a prompt fits in a context window or under a rate limit, because code, URLs, emoji and non-English text tokenize very differently from English prose.
Tweets are not average English. In our sample, 51.6% of posts carried a link, and posts mix in handles, hashtags and emoji. Those are exactly the strings where a characters-per-token rule drifts most, which is why the study below reports characters and words as measured facts and labels every token figure as an estimate.
Anthropic's docs are explicit that the same input produces different counts on different models. Claude Opus 4.7 introduced a newer tokenizer; Claude Fable 5.2, Fable 5.1, Fable 5 and the matching Mythos models share it, and a prompt counts the same on all of them, "roughly 30 percent higher than on models before Claude Opus 4.7 (the exact increase depends on the content)."
The docs' advice for migrations is to count the same request once with your current model and once with the model you plan to move to, then compare the two input_tokens values, and not to reuse token counts measured on an older model to estimate cost or context window fit. The script below does exactly that for one prompt file across several model IDs.
Per-token price and token count move together. A model with a lower per-token price can still cost more for the same text if it produces more tokens. Comparing models on price per million tokens alone hides this; compare on counted tokens times price.
Context windows are measured in the same tokens. Anthropic's pricing page says Claude 4.6 and later models (except Haiku 5.5) include the full 1M token context window at standard pricing. A prompt that fit comfortably on an older model can land closer to a limit after a tokenizer change, so recount long documents too.
import anthropic
client = anthropic.Anthropic()
text = open("system_prompt.md").read()
for model in ["claude-sonnet-4-6", "claude-opus-5-5", "claude-sonnet-5-5", "claude-haiku-5-5"]:
n = client.messages.count_tokens(
model=model,
messages=[{"role": "user", "content": text}],
).input_tokens
print(f"{model:22s} {n:>8,} tokens")From token count to cost: the formula
Input cost is input_tokens / 1,000,000 x base input price per MTok. Output cost uses the output price and the usage.output_tokens you get back; you can cap it with max_tokens but not count it in advance. Base prices from Anthropic's pricing page for the current models:
Three adjustments the formula needs. Cache reads are billed at a fraction of base input (0.05x on Opus 5.5 and Sonnet 5.5 per the pricing page), and cache writes at a premium, which count_tokens cannot see. The Batch API halves both input and output prices. And Haiku 5.5 is priced by prompt length per request, so the count of each individual request decides which row applies.
Our Claude API pricing guide has the full table, including Fable models, fast mode and caching multipliers, plus a model-by-model cost per 1,000 tweets. Use this page's counter code to get the token number and that page to price it.
Study: how many characters is a tweet you feed to Claude?
To ground the formula in real input, we pulled 1,640 recent posts from 12 organization accounts (@AnthropicAI, @claudeai, @OpenAI, @GoogleDeepMind, @github, @vercel, @NASA, @nytimes, @espn, @Reuters, @nvidia and @Docker) with the TwitterAPI.io /twitter/user/last_tweets endpoint, collected in 2026. We measured characters and words of each post's text, and the size of the full JSON object the API returns. We did not have an Anthropic key for this study, so no number below is a measured Claude token count.
The text is short. The median post is 192.5 characters and 28 words; the 90th percentile is 314 characters and the longest post in the sample ran to 1,934 characters. 21.9% of posts were longer than 280 characters, so a "280 characters per tweet" budget undercounts.
The object around it is not. A raw tweet object (author profile, entities, media variants, card data, counts) had a median of 6,344 characters. Compared with a trimmed one-line format (handle, timestamp, text, like / repost / reply / view counts), the raw object was a median 23.4x larger per post (10th percentile 9.6x, 90th percentile 78.4x), and 26.0x larger across the whole sample.
News accounts with link cards (@Reuters, @nytimes) and long-form posters (@AnthropicAI) had the heaviest objects; the raw size is driven by attached metadata, not by how much the account writes.

What the study means for a tweets-to-Claude budget
Per 1,000 tweets, the trimmed format came to 313,146 characters and the raw JSON to 8,153,310 characters (measured). Applying Anthropic's glossary ratio (3.5 English characters per token before Claude 4.7, about 30 percent more tokens on 4.7 and later) gives the estimates below. They are a labeled formula, not counts: run count_tokens on your own prompt before you rely on them.
Trim before you count. The single largest saving in the table is not the model choice but the format: about 26x fewer characters for the same tweets. An estimated 3 million tokens of raw JSON per 1,000 tweets would not even fit in one 1M-token context window; the trimmed version fits comfortably.
Text length has a long tail. 21.9% of posts ran past 280 characters (the histogram below), so budget on a measured average, not on the classic tweet limit. Media matters too: 20.5% of posts carried a photo and 25.6% a video; if you pass images to Claude, they are counted as image tokens on top of the text (send them as base64 so count_tokens can see them).
The data side of the bill. Fetching the tweets themselves on TwitterAPI.io is $0.15 per 1,000 tweets returned (15 credits per tweet); the official X API pay-per-usage rate card on docs.x.com lists $0.005 per post read, which is $5 per 1,000 posts, about 33x more. With a trimmed format, the Claude side and the data side of a 1,000-tweet summary are the same order of magnitude.
def trim(t):
# one line per tweet: handle, time, text, counts (fields from /twitter/user/last_tweets)
a = t.get("author") or {}
return (f"@{a.get('userName','')} {t.get('createdAt','')}: {t.get('text') or ''} "
f"(likes {t.get('likeCount', 0)}, reposts {t.get('retweetCount', 0)}, "
f"replies {t.get('replyCount', 0)}, views {t.get('viewCount', 0)})")
How we collected this
Question. How much text, and how much surrounding JSON, does a typical post contain when you fetch it to feed to Claude?
Accounts and endpoint. 12 public organization accounts: @AnthropicAI, @claudeai, @OpenAI, @GoogleDeepMind, @github, @vercel, @NASA, @nytimes, @espn, @Reuters, @nvidia and @Docker. One endpoint, /twitter/user/last_tweets (default, replies excluded), newest first, up to 8 pages of 20 per account. The @GoogleDeepMind and @github timelines ended early (20 and 40 posts), so @nvidia and @Docker were added during collection; @nvidia returned 140 unique posts.
Window and size. The most recent posts of each account at collection time, collected in 2026: 1,640 unique posts from 83 requests, costing about $0.25 at 15 credits per tweet returned.
Metrics. Characters (Python string length) and whitespace-separated words of text; presence of links, photos, videos, quotes and reposts; characters of the compact JSON serialization of each tweet object; characters of a trimmed one-line format. Token and cost figures are derived with Anthropic's published ratio and are labeled as estimates.
What the sample cannot show. It measures organization accounts, which post more links and media than most individuals; replies and private accounts are excluded. It does not measure Claude tokens: we had no Anthropic key, and the characters-per-token ratio for handles, URLs and emoji can differ from English prose. Run count_tokens on your own data for real numbers.
Privacy. Aggregates only, organization accounts only; no analysis of reposted or quoted authors; the published sample file holds de-identified rows (no IDs, URLs, text or handles of individuals).
import os
import requests
import anthropic
TWITTERAPI_KEY = os.environ["TWITTERAPI_IO_API_KEY"] # docs.twitterapi.io
BASE = "https://api.twitterapi.io"
claude = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
MODEL = "claude-sonnet-5-5"
INPUT_USD_PER_MTOK = 2.00 # platform.claude.com pricing, Sonnet 5.5 base input
def fetch_timeline(user, max_pages=5):
"""Newest-first posts from one account; 20 per page."""
tweets, cursor = [], ""
for _ in range(max_pages):
r = requests.get(
f"{BASE}/twitter/user/last_tweets",
headers={"X-API-Key": TWITTERAPI_KEY},
params={"userName": user, "cursor": cursor},
timeout=30,
)
r.raise_for_status()
body = r.json()
if body.get("status") != "success":
raise RuntimeError(body.get("msg"))
data = body.get("data") or {}
tweets += data.get("tweets") or []
if not body.get("has_next_page"):
break
cursor = body.get("next_cursor") or ""
return tweets
def trim(t):
a = t.get("author") or {}
return (f"@{a.get('userName','')} {t.get('createdAt','')}: {t.get('text') or ''} "
f"(likes {t.get('likeCount', 0)}, reposts {t.get('retweetCount', 0)}, "
f"replies {t.get('replyCount', 0)}, views {t.get('viewCount', 0)})")
def count(prompt):
return claude.messages.count_tokens(
model=MODEL,
system="Summarize the main themes in these tweets in five bullet points.",
messages=[{"role": "user", "content": prompt}],
).input_tokens
tweets = fetch_timeline("AnthropicAI")
trimmed = "\n".join(trim(t) for t in tweets)
n = count(trimmed)
print(f"{len(tweets)} tweets -> {n:,} input tokens on {MODEL}")
print(f"input cost of one summary request: ${n / 1_000_000 * INPUT_USD_PER_MTOK:.4f}")
if n < 150_000: # your own budget guard
msg = claude.messages.create(
model=MODEL,
max_tokens=2000,
system="Summarize the main themes in these tweets in five bullet points.",
messages=[{"role": "user", "content": trimmed}],
)
print("billed input tokens:", msg.usage.input_tokens)
print(next(b.text for b in msg.content if b.type == "text"))Researching this?Free starter credits cover end-to-end testing — Google sign-in, no card. Get a key.
Questions readers ask
Is there an official Claude token counter?
Yes. Anthropic's Messages API has a token counting endpoint, POST https://api.anthropic.com/v1/messages/count_tokens, exposed as client.messages.count_tokens() in the Python SDK and client.messages.countTokens() in TypeScript. It takes the same input as a Messages request and returns input_tokens.
Does counting Claude tokens cost money?
No. Anthropic's docs say token counting is free to use, subject to a requests-per-minute limit by usage tier (5,000 on Start, 10,000 on Build, 20,000 on Scale). That limit is separate from message creation, so counting does not reduce your Messages quota.
Can I use tiktoken to count Claude tokens?
Only as a rough approximation. tiktoken's README describes it as a BPE tokenizer for OpenAI's models, so its counts follow OpenAI's encoding, not Claude's. For an exact number, call Anthropic's count_tokens endpoint with the model you will use.
How many characters is one Claude token?
Anthropic's glossary says a token represents approximately 3.5 English characters on models before Claude 4.7, and that Claude 4.7 and later models produce approximately 30 percent more tokens for the same text. The ratio depends on the model and the language, so use it for budgeting only.
Why does the same prompt give different counts on different Claude models?
Counts are model-specific. Claude Opus 4.7 introduced a newer tokenizer shared by later models, which produces roughly 30 percent more tokens than earlier models for the same text. Anthropic recommends counting with the model ID you plan to use and not reusing counts from an older model.
Does count_tokens include images, PDFs and tools?
Yes for client tools, the advisor tool, and images and PDFs sent as base64. It returns an error for other server tools (web search, web fetch, code execution, tool search), the MCP connector, and image or document blocks with a url or file source.
Can I count output tokens before sending a request?
No. count_tokens returns input tokens only. Output tokens are reported in usage.output_tokens on the Messages response; cap them with max_tokens and budget the worst case at the model's output price.
How many tokens are 1,000 tweets?
It depends on the format. In our study (collected in 2026) 1,000 tweets in a trimmed one-line format came to 313,146 characters, an estimated ~116,311 tokens on Claude 4.7 and later using Anthropic's published ratio; the raw API JSON was about 26x larger. Count your own prompt with count_tokens for the exact figure.
Continue
- Anthropic docs: Token counting (endpoint, supported inputs, estimate note, free usage, RPM by tier)
- Anthropic API reference: messages count_tokens (request and input_tokens response)
- Anthropic docs: Pricing (per-MTok rates, batch, caching multipliers, tool-use system prompt tokens)
- Anthropic docs: Glossary, Tokens (about 3.5 English characters per token before Claude 4.7; about 30 percent more tokens after)
- openai/tiktoken README: a BPE tokenizer for OpenAI's models
- X developer docs: pay-per-usage pricing ($0.005 per post read)
- Twitter (X) API hub: endpoints, pricing and guides
- Claude API pricing: every model's rates and cost per 1,000 tweets
- How to get and secure a Claude API key
- Claude Agent SDK: build agents on Claude Code's harness
- Which Claude model to pick for coding work
- OpenRouter API: routing requests across Claude and other models
- Connect Claude to Twitter (X) data through MCP
- TwitterAPI.io pricing: $0.15 per 1,000 tweets returned
- 01Can People See Your Twitter (X) Bookmarks? What Others See, and the One Public Number
- 02ChatGPT vs Grok: plans, models, and the real difference on Twitter (X) data
- 03IFTTT Alternatives in 2026: Which Can Still Trigger on a New Twitter (X) Post
- 04Buffer Alternatives in 2026: Which Schedulers Still Post to Twitter (X), and the DIY Route
- 05GitHub Copilot vs Claude Code: Plans, Agent Modes, Models and MCP (with Live Twitter (X) Data)
- 06Claude Cowork vs Claude Code: Which Anthropic Agent Fits Your Work (and Your Twitter (X) Data)?
- 07Codex vs Claude Code: Plans, Usage Limits, MCP Setup and Headless Runs for Twitter (X) Data Agents
- 08claude-mem: the persistent memory plugin for Claude Code, explained and measured on Twitter (X)
Writing about something you built with TwitterAPI.io? Our community rewards program pays API credits for honest tutorials, build logs and videos.
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API keyAlready building with TwitterAPI.io? Publish an honest tutorial or build log about it and earn up to $200 a month in API credits.