# Unprofane > A profanity and toxicity API that is hard to fool: one call answers whether a text can be shown (profanity, insults, slurs, threats, sexual content, sexual content involving a minor, which every policy blocks, and rudeness and the writer's own self-harm, which a standard policy holds for review), with the evidence (which words, where, how they were disguised, how severe), a one-sentence reason and a censored version. A byte-compatible drop-in for Google's Perspective API at `/v1alpha1/comments:analyze`: the same request, response and error envelope, the key accepted as `?key=`. Texts the model reads are kept for 90 days to improve the engine, with no account, key or sender's address; no log holds one. The rules read every text at the edge. In balanced mode, the default, the model also reads every text but a word or two the rules block outright; fast mode keeps a check on the rules alone. Every response says which answered. Base URL: https://api.unprofane.com. Auth: `Authorization: Bearer up_live_…`. The MCP server is at https://api.unprofane.com/mcp. The full docs in one file: https://unprofane.com/llms-full.txt ## Start - [Overview](https://unprofane.com/docs/) - [Quickstart](https://unprofane.com/docs/quickstart/) - [Examples](https://unprofane.com/docs/examples/) ## Guides - [Modes](https://unprofane.com/docs/modes/): Which mode to send with a check: what fast, balanced and thorough each ask of the rules and the model, what each was measured to catch, and what each costs in time and privacy. - [Nakama](https://unprofane.com/docs/nakama/): A Nakama server module, in TypeScript, Go and Lua, that checks chat messages, usernames, display names and group names before other players see them. - [Languages](https://unprofane.com/docs/languages/): The languages Unprofane reads, each with its own word list, and how well each one is measured: items in the open Scunthorpe Test and judged texts in the development set, with what each number leaves out. - [Contexts](https://unprofane.com/docs/contexts/): What the text is changes how it is read. Usernames are split into words and checked backwards; comments are read as prose. - [Policies](https://unprofane.com/docs/policies/): How strict to be. Four presets, or your own map of category to allow, review or block, saved on the project. - [Evasion tags](https://unprofane.com/docs/evasion-tags/): Every way a writer disguises a word is normalized and named in the response, so you can see how the filter was fooled and choose what to do about it. - [Engine versions](https://unprofane.com/docs/engine-versions/): Versions are dated and immutable. Pin one per project or per request, read the changelog, and replay a sample before you move. - [Lists](https://unprofane.com/docs/lists/): Allow, block and reserved lists per project, from the dashboard or the API. Terms are folded the way the engine folds text, so a listed word matches its disguises too. - [Publishable keys](https://unprofane.com/docs/publishable-keys/): A key that may live in a browser or a game client, limited to /v1/check and to the origins you allow, with a per-address limit. - [Edge-only projects](https://unprofane.com/docs/edge-only/): A project setting that guarantees no text is ever sent to a model. The model client is not constructed, so no code path can reach it. - [Rate limits and quotas](https://unprofane.com/docs/rate-limits/): Bursts per key per minute by plan, the monthly allowance, what happens past it, how test keys are capped, and what a key does with no plan. - [Batch checks](https://unprofane.com/docs/batch/): Up to 100 texts and 30,000 characters in one request, each text with its own id, answered in order. One bad item never fails the batch. - [Feedback](https://unprofane.com/docs/feedback/): Send a correction when a result is wrong. Corrections feed the lexicon, the innocent list and the calibration, never a silent change inside a pinned version. - [Perspective API compatibility](https://unprofane.com/docs/perspective-migration/): The exact contract of the Perspective-compatible endpoint. What is the same as Google's API, request for request and error for error, and what is not. - [Azure Content Moderator migration guide](https://unprofane.com/docs/azure-content-moderator/): Move a Content Moderator text screen to /v1/check, field by field. The request, the Terms your code reads, the language codes, your term lists, a staging check and a rollback. - [Privacy for developers](https://unprofane.com/docs/privacy/): What the API keeps, for how long, and what it never keeps, in the terms a developer needs to answer their own users and their own lawyer. - [SDKs](https://unprofane.com/docs/sdks/): The JavaScript and Python clients: typed, no dependencies beyond the runtime, retries with jitter, and a batch helper for any number of texts. - [MCP server](https://unprofane.com/docs/mcp/): The same engine as a Model Context Protocol server, for coding agents and assistants. Five tools, the same keys, Streamable HTTP. ## Reference - [API reference](https://unprofane.com/docs/api/) - [Errors](https://unprofane.com/docs/errors/) - [openapi.json](https://unprofane.com/openapi.json) - [llms-full.txt](https://unprofane.com/llms-full.txt) - [OpenAPI document](https://api.unprofane.com/openapi.json) ## Answers - [What counts as a check?](https://unprofane.com/pricing/#what-counts-as-a-check): An Unprofane check is one text item sent to the check endpoint, the batch endpoint (each item counts), the Perspective endpoint or the MCP server. - [Is there a free plan?](https://unprofane.com/pricing/#is-there-a-free-plan): Unprofane has no free plan, but its test keys are free and need no card, so you can build and test the whole integration before you pay. - [What happens at the allowance?](https://unprofane.com/pricing/#what-happens-at-the-allowance): At the allowance, Unprofane's Research plan stops until the month resets, with a clear error that says so. - [Can I limit the bill?](https://unprofane.com/pricing/#can-i-limit-the-bill): Yes: set a spend cap on Unprofane's billing page, the most overage you will pay in a period, or none at all. - [What happens when I cancel?](https://unprofane.com/pricing/#what-happens-when-i-cancel): A canceled Unprofane plan runs to the end of the period you paid for. - [What if Unprofane gets a text wrong?](https://unprofane.com/pricing/#wrong-answer): Tell Unprofane, with the check's id and what it should have said. - [Is there yearly billing?](https://unprofane.com/pricing/#yearly-billing): Yes: Unprofane's Growth and Scale can be paid a year ahead: twelve months for the price of ten, with twelve months of checks to use across the year and extra checks billed at the plan's rate with the renewal. - [Does the model cost extra?](https://unprofane.com/pricing/#does-the-model-cost-extra): No: an Unprofane check costs the same whether the rules answered it or the model did. - [Is tax added?](https://unprofane.com/pricing/#tax): Unprofane's checkout, run by Dodo Payments, adds any sales tax or VAT your country requires, and shows the total before you pay. - [Which mode should I use: fast, balanced or thorough?](https://unprofane.com/docs/modes/#which-mode): Use Unprofane's balanced mode, the default, unless a text must never reach a model; then fast for one request or an Edge-only project for all of them. - [Which languages does Unprofane support?](https://unprofane.com/docs/languages/#which-languages): Unprofane supports 17 languages, each with its own word list: Arabic, Chinese, Dutch, English, French, German, Hebrew, Hindi, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish, and Turkish. - [What should the sign-up form tell the person?](https://unprofane.com/usernames/#what-to-tell-the-person): When Unprofane blocks a username, the form should ask for another one and say no more: "Pick a different username." The response names the word, where it was and how it was disguised; keep that for your logs, because repeating it teaches the next attempt. - [Will Unprofane block real surnames and places?](https://unprofane.com/usernames/#real-names-get-through): Not the ones on Unprofane's innocent list: 1,480 words and names that contain a profane string, from Scunthorpe and Dickinson to Cumberbatch. - [Can I check a username while the person is typing?](https://unprofane.com/usernames/#check-as-they-type): Yes, with an Unprofane publishable key, which may live in a browser: it calls only the check endpoint, only from the origins you list, at 30 requests a minute per address. - [Can I check the names I already have?](https://unprofane.com/usernames/#check-existing-names): Yes: send them through Unprofane's batch endpoint, up to 100 names a request, each counted as one check. - [How do I test Unprofane on my own names before launch?](https://unprofane.com/usernames/#test-on-your-names): Run Unprofane on names you have already decided, the ones you approved and the ones you removed, kept apart. - [Should I check display names too?](https://unprofane.com/usernames/#display-names): Yes, with Unprofane's context: "display_name", which reads a name the way username does: split into words, with the disguises undone. - [What happens to sign-ups if Unprofane does not answer?](https://unprofane.com/usernames/#when-unprofane-is-down): Your code decides, and each Unprofane recipe says what it does. - [What should I use instead of the Perspective API?](https://unprofane.com/perspective/#use-instead): Unprofane, a drop-in alternative to Google's Perspective API: it answers the same request, so your integration keeps working after December 31, 2026. - [When does the Perspective API shut down?](https://unprofane.com/perspective/#when-perspective-ends): After December 31, 2026. Google's notice says the service stays active until that day, that access cannot be extended past it, and that Google will not offer direct migration support. - [Do I have to rewrite my integration?](https://unprofane.com/perspective/#rewrite-integration): No: Unprofane answers with Google's own request, response and errors, so the code that builds the request and reads attributeScores stays as it is. - [Can I switch back?](https://unprofane.com/perspective/#switch-back): Yes: until December 31, 2026, you can move from Unprofane back to Google's Perspective API by putting Google's host and your Google key back. - [Is there a free plan for research, as Perspective had?](https://unprofane.com/perspective/#research-users): Yes: Unprofane's Research plan is free, as the Perspective API was for research. - [What is different from Google's Perspective API?](https://unprofane.com/perspective/#what-is-different): Unprofane takes Google's request, response and error envelope as they are, and still accepts the key as ?key=. - [How does Unprofane compare with the Perspective API?](https://unprofane.com/perspective/#how-it-compares): On the same held-back judged texts, read once on 2026-09-28, at the same share of clean text flagged (7.0%), Unprofane caught 89.0% of 2,672 toxic texts and the Perspective API 58.4%. - [What does Unprofane cost after Perspective?](https://unprofane.com/perspective/#what-it-costs): Unprofane's Growth plan, 1,000,000 checks a month for $249, starts with 14 days free and a live key, so you can run it on your own traffic before the first charge; a card is needed and nothing is charged if you cancel in time. - [What is the Scunthorpe problem?](https://unprofane.com/guides/scunthorpe-problem/#what-is-the-scunthorpe-problem): A filter blocking innocent text because a profane string sits inside it, named for the English town whose name holds one. - [How do I filter profanity without false positives like Scunthorpe?](https://unprofane.com/guides/scunthorpe-problem/#without-false-positives): Read whole words through their disguises, rule out the innocent words that hold a profane string, and allow your own names. - [Which innocent words do profanity filters block most?](https://unprofane.com/guides/scunthorpe-problem/#innocent-words-blocked-most): Animal names and medical terms. On the Scunthorpe Test's public split, obscenity 0.4.6, the filter that flagged the most, blocked 20.2% of the innocent items: 53.2% of animal names (cockatoo, cockatiel) and 42.3% of medical terms (run of 2026-10-18). - [Why not just match whole words?](https://unprofane.com/guides/scunthorpe-problem/#why-not-whole-words): Whole words let Scunthorpe through, but they also let through a slur run into the next word, and a username has no spaces to split on. - [Can I allow town names, surnames and product names?](https://unprofane.com/guides/scunthorpe-problem/#allow-your-own-names): Yes: put them on your Unprofane project's allow list, or send them with the request. - [How do I test a profanity filter for false positives?](https://unprofane.com/guides/scunthorpe-problem/#test-for-false-positives): Run it on clean text you know and read every block: your users' towns, your product names, your community's words. - [What about a word that is innocent in one sentence and an insult in the next?](https://unprofane.com/guides/scunthorpe-problem/#innocent-in-context): Unprofane's rules cannot rule such a word out alone, so in balanced mode it goes to the model, and the answer says which of the two decided. - [When does Azure Content Moderator retire?](https://unprofane.com/azure-content-moderator/#when-content-moderator-retires): On March 15, 2027, by Microsoft's retirement notice and its Content Moderator overview. - [Does Azure AI Content Safety replace the profanity screen?](https://unprofane.com/azure-content-moderator/#is-content-safety-a-replacement): Not its term list. Microsoft's own FAQ says Content Safety doesn't have a built-in term list: it scores hate, sexual content, violence and self-harm by severity, matches only the blocklists you fill yourself, and a blocklist match names the list and the item, not where it was in the text. - [How much of my Content Moderator code changes?](https://unprofane.com/azure-content-moderator/#how-much-code-changes): With Unprofane, only the call changes, and nothing that reads its answer. - [Are the positions the same as Content Moderator's?](https://unprofane.com/azure-content-moderator/#same-positions): Yes: through Unprofane's mapping, OriginalIndex is where the word starts in the text you sent, as in Content Moderator. - [Does Unprofane read Content Moderator's languages?](https://unprofane.com/azure-content-moderator/#content-moderator-languages): Unprofane reads 17 of them, each with its own list: Content Moderator's term list had 112 language rows, and every language Unprofane reads is among them. - [What happens to my custom term lists?](https://unprofane.com/azure-content-moderator/#content-moderator-term-lists): They move to your Unprofane project's block list: up to 5,000 terms of up to 64 characters, read through the same disguises as the text. - [What does Unprofane cost after Content Moderator?](https://unprofane.com/azure-content-moderator/#cost-after-content-moderator): Unprofane's test keys are free, need no card and answer 100 checks a month across the account, enough to build the move and check it on staging. - [Is my users' text kept, and does it reach a model?](https://unprofane.com/docs/privacy/#answering-your-users) - [What each username answer means at sign-up](https://unprofane.com/usernames/#names-answers) ## Perspective API migration - [Replace the Perspective API, keep your client](https://unprofane.com/perspective/): the date, the one line that changes, a guide per client - [Move Coral Talk off the Perspective API](https://unprofane.com/perspective/coral/): Set Coral’s Custom endpoint to https://api.unprofane.com/v1alpha1 and its API key to an Unprofane key. Coral adds comments:analyze and comments:suggestscore itself. - [Move Discourse off the Perspective API](https://unprofane.com/perspective/discourse/): The discourse-perspective-api plugin hardcodes Google’s host and has no endpoint setting. Fork it, change one line, rebuild, and put an Unprofane key in perspective_google_api_key. A Discourse you cannot add plugins to cannot run the fork. - [Move a Python client off the Perspective API](https://unprofane.com/perspective/python/): Give discovery.build a discoveryServiceUrl on the Unprofane host and keep every call the same. - [Move a Node client off the Perspective API](https://unprofane.com/perspective/node/): Build the client with google.discoverAPI from the Unprofane discovery URL and keep the calls. - [Move raw HTTP calls off the Perspective API](https://unprofane.com/perspective/http/): The same POST body and the same response on the Unprofane host, with the key as ?key= or a bearer header. - [Map your thresholds](https://unprofane.com/perspective/replay/): the threshold here that keeps your review queue the same size - [Perspective API compatibility](https://unprofane.com/docs/perspective-migration/): what is byte-for-byte the same and what is not ## Azure Content Moderator migration - [Replace Azure Content Moderator's profanity screen](https://unprofane.com/azure-content-moderator/): the date, what Content Safety leaves out, the call that changes - [Azure Content Moderator migration guide](https://unprofane.com/docs/azure-content-moderator/): ProcessText/Screen to /v1/check field by field, a mapping to Terms in C#, Python, JavaScript and jq, the language codes and the term lists ## Evidence - [Every number, with its count, set, engine, run and limits](https://unprofane.com/bench/#evidence) - [What the numbers mean: false-positive rate, recall, precision, F1, and the kinds of set](https://unprofane.com/bench/#definitions) - [The Scunthorpe Test: disguised spellings and innocent words, a public split to download](https://unprofane.com/bench/scunthorpe/) - [Head to head: Unprofane, the Perspective API, OpenAI moderation and the npm filters on the same judged texts](https://unprofane.com/bench/head-to-head/) ## Blog - [Google Is Shutting Down Perspective API on December 31. Here’s What Breaks, and When](https://unprofane.com/blog/perspective-api-shutdown/): The scary part isn’t an error page. It’s a comment section that keeps running with nobody checking it. - [7 Profanity Filters for Developers in 2026 (Perspective API Is Shutting Down)](https://unprofane.com/blog/profanity-filters-for-developers/): The ones I’d actually put in front of a signup form, a chat box or a comment section. ## Optional - [Pricing](https://unprofane.com/pricing/) - [Usernames: the check, how well it reads names, and recipes per auth stack](https://unprofane.com/usernames/) - [Privacy](https://unprofane.com/legal/privacy/)