Word counter
Need a reliable word count for an article, caption, brief or mixed-language draft? This tool measures words, characters, characters without spaces, sentences, paragraphs and estimated reading time with one deterministic pass. The same rules run free in your browser and on the API, so automation never drifts from what you previewed on the page.
Run — free
What counts as a word
Words are formed from Unicode letters and numbers, not from a naive split on spaces alone. Contractions such as don't and compounds such as well-known stay together, and decimal numbers like 3.14 count as one word. Underscores and email separators do not glue tokens: foo_bar yields two words and email@example.com yields three. Empty strings and pure whitespace produce zero words, while leading and trailing spaces never invent extra tokens. The algorithm walks Unicode code points, so a single emoji is one character rather than two UTF-16 units.
Chinese, Japanese and Korean without guessing dictionaries
Scripts that do not separate words with spaces need an explicit rule. Each Han character counts as one word; contiguous runs of Kana or Hangul count as one word each. Mixed strings such as Hello followed immediately by Chinese characters split into Latin and Han tokens instead of collapsing into a single blob. Sentence endings written with fullwidth or ideographic terminators also count without requiring a following space, which matches how CJK prose is actually written. The tool does not ship a large lexical segmenter: the rules stay portable, auditable and identical on server and browser.
Sentences, paragraphs and reading time
Sentences end at ., !, ?, ellipsis and the CJK terminators, with optional closing quotes or brackets, while the decimal point inside 3.14 does not start a new sentence. Paragraphs are blocks of non-empty lines separated by blank lines; a single line break inside a block stays one paragraph. Reading time uses your words-per-minute setting (default 200) and rounds up to whole seconds, or zero when there are no words. Use the JSON fields directly in editors, SEO checks, CMS validations or any pipeline that needs a stable count rather than a browser-only estimate.
What you can do with it
Editorial and SEO length checks
Measure titles, meta descriptions and body copy before publishing so length targets stay consistent across authors.
Multilingual drafts
Count mixed Latin and CJK text with explicit rules instead of treating every ideograph as invisible or as one giant word.
Automation and CMS hooks
Call the API with the same contract as the free widget to reject empty posts or estimate reading time in a pipeline.
Accessibility previews
Surface characters, sentences and reading time next to a draft so reviewers see structure, not only raw length.
FAQ
Is the online word counter free?
Yes. The browser tool runs locally at no charge. API requests use prepaid KIT balance at the published $0.002 base price; failed tasks are not charged.
How are words counted?
The counter uses Unicode letter and number runs with explicit joiners for apostrophes, hyphens and decimal points. It does not rely on Intl.Segmenter, so results stay aligned between browser and server.
How does Chinese or Japanese counting work?
Each Han character is one word. Contiguous Kana or Hangul form one word per run. Sentence terminators such as 。 and ! close sentences even when the next character is not a space.
Does 3.14 create two sentences?
No. A single decimal point between digits is kept inside the number for both word and sentence rules.
What does reading_time_seconds mean?
It is ceil(words × 60 / wpm). The default wpm is 200; set wpm to any finite number greater than zero to change the estimate.
What is the maximum text size?
Up to 500,000 Unicode characters per request. Larger documents should be split before counting.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/text/word-count \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Hello world. How many words is this?"}'const res = await fetch("https://api.kit.forhosting.com/text/word-count", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "Hello world. How many words is this?"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/text/word-count",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "Hello world. How many words is this?"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/text/word-count", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"Hello world. How many words is this?"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"Hello world. How many words is this?"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/text/word-count", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "Hello world. How many words is this?"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "text.word_count",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_chars | 500000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |