zero-shot text classification over plain HTTP — no API key, no account
## Give your agent this prompt #
Paste it into any coding agent. It installs the skill and teaches the agent to classify text through this API — no key, no setup.
Set up the classifier.dev skill: run `npx skills add https://classifier.dev`, then read https://classifier.dev/skill.md and follow it all the way through.
or open it in[Claude Code][Codex][Cursor][Grok]
## Better than calling its own model directly #
The model behind this service is Jev. The smart tier re-asks only what Jev was unsure about, and comes out +2.5 points on AG News (+18.4 on the unsure items), +1.0 points on emotion (+4.9 on the unsure items). On 400 items a gap under about 5 points is noise; AG News clears it. Same public test sets, measured live over this API on 2026-09-18. No key, no cost.
| AG News | emotion | |||
|---|---|---|---|---|
| all | unsure (49) | all | unsure (122) | |
| jev alone = classifier.dev fast | 87.5% | 65.3% | 61.8% | 36.9% |
| classifier.dev smart | 90.0% | 83.7% | 62.7% | 41.8% |
## Try it #
curl https://classifier.dev/spam,not+spam/Win+a+free+iPhone
spam
## Install the CLI #
npm i -g classifier-dev
Then sort a file, one label ⇥ confidence ⇥ text line per input, in input order — a thousand lines a request, and rows appear as they land:
classify bug,feature,praise < feedback.txt
classify relevant,"not relevant" --review 0.7 < snippets.txt # only the unsure ones
Zero-shot text classification over plain HTTP. You send text and a list of labels, you get back the label that fits and how sure the model is. There is no API key to obtain and no account to create, so the example below works if you paste it right now.
If you are an agent or a code generator, the machine-readable description of this API lives at https://classifier.dev/openapi.json (OpenAPI 3.1), with a short index at https://classifier.dev/llms.txt
## Against the model it runs on #
The model behind this service is Jev; the smart tier re-asks what Jev was unsure about. Same public test sets, 400 items each, measured live on 2026-09-18:
AG News emotion
all unsure(49) all unsure(122)
-------------------------------------------------------------------------
jev alone = classifier.dev fast 87.5% 65.3% 61.8% 36.9%
classifier.dev smart 90.0% 83.7% 62.7% 41.8%
The fast tier is Jev, so one row serves both. Smart re-asked 43 / 126 of 400 items. Gaps under about 5 points are noise. The full table, with latency and cost, is at https://classifier.dev/benchmark
## When this is worth a network call #
If you are a language model, you can already classify any text you can see, for free. So the question is never "can I classify this" — it is whether you want the text in your context at all.
This is worth calling when reading the input is the expensive part:
Filtering before reading. You have forty search results and want the six worth opening. Judging them yourself means pulling all forty into context first, which is the cost you were trying to avoid. One call returns forty labels and you read only the survivors.
Cascade pre-filtering. Drop the obvious no's cheaply, then spend real reasoning on what is left.
Streams nobody reads line by line. Log lines, error buckets, inbound tickets, the changed files in a large diff.
Deterministic routing. A pipeline branch that must take the same path for the same input on every run, instead of drifting with a model's reasoning.
The thread joining those: classify ten thousand things without reading them yourself. A thousand inputs go in one request and come back in about a second. Below about five items, skip it — you have already paid the context cost, so just decide.
## CLI #
The same API from the shell, one line per input, in input order:
npm i -g classifier-dev
classify bug,feature,praise < feedback.txt
classify relevant,"not relevant" --review 0.7 < snippets.txt # the unsure ones
classify db,web,ml --count < titles.txt # a histogram
Plain lines, JSON or NDJSON in; label, confidence and text out. Batches of a thousand per request, four at a time, and rows stream as they land, so piping to head returns at once on a large file. Retries rate limits and upstream failures on its own. classify --help has the rest. Source in cli/ at https://github.com/mrmps/classifier-dev
## MCP #
The same tools inside Claude, ChatGPT, Codex, Cursor or any MCP client, over Streamable HTTP with no key:
https://classifier.dev/mcp classify_texts, classify_multi_label, count_labels, review_uncertain
https://classifier.dev/mcp/docs list_docs, read_doc, search_docs
claude mcp add --transport http classifier https://classifier.dev/mcp
codex mcp add classifier --url https://classifier.dev/mcp
Listed in the official MCP registry as dev.classifier/classifier and dev.classifier/docs: https://registry.modelcontextprotocol.io/v0/servers?search=dev.classifier
Claude.ai: Customize > Connectors > Add custom connector > paste the URL. ChatGPT: Settings > Security and login > Developer mode, then create an app with the URL and "No Authentication". Step by step for every client, plus what each tool does: https://classifier.dev/mcp-setup
## Agent skill #
Install this as a skill and your agent will remember to reach for it:
npx skills add https://classifier.dev
It is served straight from this domain over RFC 8615 well-known discovery, so there is no repository in the middle:
/.well-known/agent-skills/index.json the discovery document
/skill.md the skill itself, readable as-is
Agents without a skills runtime can simply fetch /skill.md and follow it.
## Usage #
GET https://classifier.dev/{labels}/{text}
GET https://classifier.dev/?labels={a,b}&text={text}
POST https://classifier.dev {"input":"...","labels":["...","..."]}
POST https://classifier.dev {"inputs":["...", ...up to 1000],"labels":[...]}
## Examples #
curl https://classifier.dev/spam,not+spam/Win+a+free+iPhone+now
spam
curl classifier.dev -d '{"input":"the checkout button does nothing","labels":["bug","feature","praise"]}'
{"label":"bug","confidence":1,"scores":{"bug":1,"feature":0,"praise":0},"model":"jev-1.13.0","ms":260}
curl "classifier.dev/entailment,neutral,contradiction/Only+12+of+40+sites+were+inspected.+Every+site+was+inspected."
contradiction
Spaces can be written as + or %20, and labels are separated by commas.
The same request as query parameters, for code that builds URLs:
curl "https://classifier.dev/?labels=spam,not+spam&text=Win+a+free+iPhone+now";
spam
input, q, classes and categories are read as text and labels too, and the two forms mix: /spam,not+spam?text=... is the same call. Every option below works on both. A malformed GET answers with a URL that would have worked.
## Parameters #
labels Two to one hundred categories. Required.
input The text to classify, up to 32,000 characters.
inputs Up to one thousand strings classified in a single call.
tier Either fast (the default) or smart. See TIERS.
instructions Extra criteria, such as "judge the reviewer's overall verdict".
verbose On GET requests, ?verbose=1 returns JSON instead of a bare label.
multi Return every category that applies instead of just one.
max_labels Cap how many multi-label answers come back.
Results come back in input order. Each carries the label, a confidence from 0 to 1, a score for every label, and the model that answered.
Batch responses also carry modelsUsed. The top-level model is "mixed" when different results were answered by different models, such as a smart-tier batch where only some inputs were escalated.
## Confidence #
The model behind this is not a language model prompted to classify. It is a decision model that returns a calibrated probability for every label, so the confidence is a real forecast of whether the label is right, measured:
six-way emotion, 400 items confidence >= 0.9 right 82% of the time
confidence < 0.5 right 29% of the time
four-way news topic, 400 items confidence >= 0.9 right 92% of the time
confidence < 0.5 right 64% of the time
Use it. Act on high-confidence answers, and route the rest to a person, a reasoning model, or the smart tier, which does exactly that for you.
Two things confidence does not measure.
It is not out-of-distribution detection. It says which of your labels fits best, not whether any of them fit. "The weather is nice today" against bug / feature / praise is "praise" at 0.97. If none-of-the-above is a real outcome, add it as a label — the same text against those three plus "none of these" picks "none of these" at 0.78. That works; hoping for a low score does not.
It is withheld for input that is not language. A forced choice on "asdkjfhaskdjfh" still lands somewhere, so the label ships with confidence and scores null and an unscored field explaining why.
## Multi-label #
One article, fifty tags, the ones that fit:
curl classifier.dev -d '{"input":"...","labels":["ml","databases",...],
"multi":true,"max_labels":10}'
{"results":[{"labels":["databases","serverless","rust","caching", ...],
"scores":{"databases":0.98,"serverless":0.98,...,"gaming":0.01}}]}
On GET, add ?multi=1 and the labels come back one per line.
Every label is judged independently as a yes/no probability, and the answer lists those at or above 0.7, most likely first. The full score map is returned so you can set your own threshold: on a seven-task set, 0.7 gave recall 0.99 and precision 0.81 (F1 0.887); 0.5 gave recall 1.00 and precision 0.74. max_labels keeps the top N. One request, about 200ms.
## Tiers #
fast Every answer comes from the decision model, in one round trip.
Measured: four-way news topic 87.7%, six-way emotion 60.5%, which is
the same accuracy as a 3.4-second reasoning model on the news topics
at two milliseconds per item.
smart Same first pass, then every single-label answer below 0.7 confidence
is re-asked of a fast reasoning model and replaced. Measured:
emotion 61.8% to 63.7%, news topics 87.5% to 90.0%, by re-asking
30% and 12% of the items. Those results carry escalated: true and
the reasoning model's name; the confidence and scores shown are
still the decision model's, since they are why it was escalated.
usage.escalated counts them. A few seconds per escalated item, so
a batch on smart is slower in proportion to how uncertain it is.
Multi-label answers ignore the tier: the reasoning model was
measured re-judging them and made them worse.
The models are not fixed. They are benchmarked as candidates appear and swapped when a measurement, not a launch post, says to. If the decision model is unavailable, requests of up to twenty inputs fall back to a chain of language models on different providers; JSON responses always report which model actually answered.
## Limits #
Limits are counted per IP address in classifications, not requests, so a batch of a thousand inputs spends a thousand of them. The fast tier allows 3,000 per minute and 20,000 per day; the smart tier 200 per minute and 2,000 per day.
Each input is capped at 32,000 characters, and a request may carry up to a thousand inputs. Every response carries an X-RateLimit-Limit header and, where it can be determined, X-RateLimit-Remaining. Exceeding a limit returns 429 with a Retry-After header rather than a slow or silently dropped request.
If you need more than this, or you want a classifier tuned to your own data, the fastest path is a short call: https://cal.com/michaelsf/coffee
## Privacy #
The text you send is never stored or logged here. It is forwarded to the model provider for the classification and nothing else. What gets recorded is the label names, which tier ran, which model answered, the latency, the response status and a coarse country, which is what makes the usage counts on this service possible.
Built by @michael_chomsky — https://x.com/michael_chomsky