Not whether a listed word appears, but whether the text can be shown, to which audience, and why.
A number of hosted services take a text and return a boolean or a list of matched words from a fixed list, often with a free tier and a flat price.
Hosted word-list APIs are not on the benchmark, so they have no bar and this page makes no claim about their accuracy. When you compare, ask for toxic text caught at a stated false-alarm rate, on text nobody tuned on.
The private test set, 9,029 texts labelled blind, read once on 2026-09-28, engine 2026-09-29. How it was measured
The real engine, live. Type a disguised word and watch it read, named and judged; type an innocent one and watch it pass.
Every answer carries the same evidence through the API: the words, where they were, how they were disguised and a censored version.
01
Split into words and read backwards, so a reversed word is caught and a reserved name is told apart from a rude one.
username
kcuffuck
reversedreview ยท strong
Shown as ****
02
Kids, teen, standard and strict presets, with each category scored apart, so the same text can pass for adults and stop for children.
03
False positives on innocent words are counted and published, per engine version.
0.0%
false positives on 1,447 innocent words and phrases, the Scunthorpe Test of 2026-10-12
Not just whether a word is on a list: whether the text can be shown, to whom, and why.
A test key is free, with a plan or without one. One request, in the language you use, and the answer carries the evidence.
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"}'const res = await fetch('https://api.unprofane.com/v1/check', {
method: 'POST',
headers: { Authorization: 'Bearer up_test_YOUR_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
"text": "xXsh1tXx",
"context": "username",
"policy": "teen"
}),
});
const result = await res.json();import httpx
r = httpx.request(
"POST",
"https://api.unprofane.com/v1/check",
headers={"Authorization": "Bearer up_test_YOUR_KEY"},
json={
"text": "xXsh1tXx",
"context": "username",
"policy": "teen",
},
timeout=5.0,
)
result = r.json()req, _ := http.NewRequest("POST", "https://api.unprofane.com/v1/check",
strings.NewReader(`{"text":"xXsh1tXx","context":"username","policy":"teen"}`))
req.Header.Set("Authorization", "Bearer up_test_YOUR_KEY")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)$res = file_get_contents('https://api.unprofane.com/v1/check', false, stream_context_create(['http' => [
'method' => 'POST',
'header' => "Authorization: Bearer up_test_YOUR_KEY\r\nContent-Type: application/json\r\n",
'content' => '{"text":"xXsh1tXx","context":"username","policy":"teen"}',
]]));
$result = json_decode($res, true);require 'net/http'; require 'json'
uri = URI('https://api.unprofane.com/v1/check')
req = Net::HTTP::Post.new(uri, 'Authorization' => 'Bearer up_test_YOUR_KEY', 'Content-Type' => 'application/json')
req.body = '{"text":"xXsh1tXx","context":"username","policy":"teen"}'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
result = JSON.parse(res.body)using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "up_test_YOUR_KEY");
var req = new HttpRequestMessage(HttpMethod.Post, "https://api.unprofane.com/v1/check");
req.Content = new StringContent("{\"text\":\"xXsh1tXx\",\"context\":\"username\",\"policy\":\"teen\"}", Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
var result = await res.Content.ReadFromJsonAsync<JsonElement>();var http := HTTPRequest.new()
add_child(http)
http.request_completed.connect(func(_r, _code, _h, body):
var result = JSON.parse_string(body.get_string_from_utf8())
print(result))
http.request("https://api.unprofane.com/v1/check",
PackedStringArray(["Authorization: Bearer up_test_YOUR_KEY", "Content-Type: application/json"]),
HTTPClient.METHOD_POST, "{\"text\":\"xXsh1tXx\",\"context\":\"username\",\"policy\":\"teen\"}")Free test keys, 100 checks a day, no card. Live from $9 a month. Every answer shows its evidence.