Unprofane
DocsQuickstart

A first check in two minutes

Sign in, copy the test key, send one request, read the answer.

1. Get a key

Sign in with your email. The link creates your account and shows a test key once: up_test_…. Test keys are for building and never billed: 100 checks a day across the account, with a plan or without one. When you ship, choose a plan (from $9 a month) and make a live key in the dashboard; live and publishable keys answer only on a plan.

2. Send a text

Replace the key, run it. The username xXsh1tXx is checked against the teen policy.

curl -X POST https://api.unprofane.com/v1/check \
  -H "Authorization: Bearer up_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"xXsh1tXx","context":"username","policy":"teen"}'

3. Read the answer

{
  "id": "chk_…",
  "allowed": false,
  "action": "block",
  "score": 0.9,
  "severity": "strong",
  "categories": { "mild_profanity": 0, "profanity": 0.9, "sexual": 0, "insult": 0, "slur": 0, "threat": 0, "rude": 0, "sexual_minors": 0, "self_harm": 0, "reserved": 0 },
  "obfuscated": true,
  "evasion": ["leetspeak"],
  "matches": [
    { "start": 2, "end": 6, "text": "sh1t", "normalized": "shit", "term_id": "en:shit",
      "category": "profanity", "severity": "strong", "evasion": ["leetspeak"] }
  ],
  "censored": "xX****Xx",
  "language": { "detected": "en", "confidence": 0.6 },
  "engine": { "version": "2026-09-29", "route": "rules", "degraded": false },
  "timing_ms": 1
}
  • action is what to do: allow, review or block. allowed is the same answer as a boolean.
  • matches is the evidence: the span in the original, what was typed, what it normalised to, and the evasion tags that got it there. Here sh1t was read as shit through leetspeak.
  • censored is ready to display.
  • engine.route says who answered: the rules at the edge, the model, or the cache. degraded is true when the model was wanted and unavailable, and the rules answered alone.

4. Choose a context and a policy

context tells the engine what the text is; usernames are split into words and read backwards, comments are read as prose. policy is how strict to be: kids, teen, standard or strict, or your own map of category to action. Both can be set as project defaults in the dashboard so a request can leave them out.

5. Ship it

Keep the secret key on your server. For a username field checked from the browser, make a publishable key with your site's origin allowed. Copy-paste recipes for Supabase, Clerk, Firebase, Auth0, Better Auth, Unity and Godot are on the username page.