Unprofane

Perspective API tester

Send a comments:analyze request to the drop-in endpoint and read the response as your code will.

POST /v1alpha1/comments:analyze Perspective API request
43 / 20,480 bytes
requestedAttributes
No key needed here. Ctrl or ⌘ Enter sends.
Request body
{
  "comment": {
    "text": "You are an idiot and nobody wants you here."
  },
  "requestedAttributes": {
    "TOXICITY": {},
    "INSULT": {},
    "PROFANITY": {},
    "THREAT": {}
  },
  "doNotStore": true
}
Response

Send the request to see the response.

The scores land here as bars, and the JSON as the endpoint sends it: attributeScores, languages, detectedLanguages.

The scores are Unprofane's, in Google's format.

Every production attribute, scored

Each scored from 0 to 1, with span scores by sentence on request. Google’s experimental names read as the attribute they became.

AttributeWhat it scoresAlso answers to
TOXICITYRude, hostile or unreasonable enough to drive someone out of a conversation.TOXICITY_EXPERIMENTAL
SEVERE_TOXICITYVery hateful or aggressive. Far less moved by mild swearing than TOXICITY.SEVERE_TOXICITY_EXPERIMENTAL
IDENTITY_ATTACKHateful or demeaning about a person for who they are: race, religion, gender, sexuality, disability.IDENTITY_ATTACK_EXPERIMENTAL
INSULTInsulting, belittling or name-calling, aimed at a person or a group.INSULT_EXPERIMENTAL
PROFANITYSwearing, curse words and other obscene language.PROFANITY_EXPERIMENTALOBSCENE
THREATWishes or intends harm on a person or a group.THREAT_EXPERIMENTAL
SEXUALLY_EXPLICITSexual acts, body parts or other lewd content.SEXUALLY_EXPLICIT_EXPERIMENTALFLIRTATION

Not served, and refused in Google’s words unless the request sets dropUnsupportedAttributes:

  • ATTACK_ON_AUTHOR
  • ATTACK_ON_COMMENTER
  • INCOHERENT
  • INFLAMMATORY
  • LIKELY_TO_REJECT
  • SPAM
  • UNSUBSTANTIAL
  • AFFINITY_EXPERIMENTAL
  • COMPASSION_EXPERIMENTAL
  • CURIOSITY_EXPERIMENTAL
  • NUANCE_EXPERIMENTAL
  • PERSONAL_STORY_EXPERIMENTAL
  • REASONING_EXPERIMENTAL
  • RESPECT_EXPERIMENTAL

Move before December 31, 2026

Change one line and keep your client. Each client below is its guide’s own tested code.

What changes

google-api-python-client
client = discovery.build("commentanalyzer","v1alpha1",developerKey=os.environ["UNPROFANE_KEY"],  # up_test_YOUR_KEY on staging, up_live_YOUR_KEY in productionRemove: discoveryServiceUrl="https://commentanalyzer.googleapis.com/$discovery/rest?version=v1alpha1",Add: discoveryServiceUrl="https://api.unprofane.com/$discovery/rest?version=v1alpha1",static_discovery=False,)response = client.comments().analyze(body={"comment": {"text": "you are a clown"},"requestedAttributes": {"TOXICITY": {}},"languages": ["en"],"doNotStore": True,}).execute()

1 line changes. Give discovery.build a discoveryServiceUrl on the Unprofane host and keep every call the same.

Tested with google-api-python-client 2.201.0, on every run of the snippet checks. The Python guide

googleapis
const client = await google.discoverAPI(Remove: 'https://commentanalyzer.googleapis.com/$discovery/rest?version=v1alpha1',Add: 'https://api.unprofane.com/$discovery/rest?version=v1alpha1',);const res = await client.comments.analyze({key: process.env.UNPROFANE_KEY, // up_test_YOUR_KEY on staging, up_live_YOUR_KEY in productionresource: {comment: { text: 'you are a clown' },requestedAttributes: { TOXICITY: {} },languages: ['en'],doNotStore: true,},});

1 line changes. Build the client with google.discoverAPI from the Unprofane discovery URL and keep the calls.

Tested with googleapis 185.0.0, on every run of the snippet checks. The Node.js guide

Configure, Moderation, Toxic comment filter
Toxic comment filter: OnRemove: API key:              YOUR_GOOGLE_KEYAdd: API key:              up_test_YOUR_KEYRemove: Custom endpoint:      (empty)Add: Custom endpoint:      https://api.unprofane.com/v1alpha1Toxicity model:       TOXICITY (or empty)

2 lines change. 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.

Tested with Coral 9.11.8 itself, run on October 13, 2026. The Coral Talk guide

lib/discourse_perspective.rb, in your fork
Remove: GOOGLE_API_DOMAIN = "https://commentanalyzer.googleapis.com"Add: GOOGLE_API_DOMAIN = "https://api.unprofane.com"
Site settings
perspective_enabled:        trueRemove: perspective_google_api_key: YOUR_GOOGLE_KEYAdd: perspective_google_api_key: up_test_YOUR_KEYperspective_toxicity_model: standard

2 lines change. 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.

Tested with Discourse 2026.10.0-latest itself, run on October 13, 2026. The Discourse guide

Any HTTP client
Remove: curl -X POST "https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=YOUR_GOOGLE_KEY" \Add: curl -X POST "https://api.unprofane.com/v1alpha1/comments:analyze?key=up_test_YOUR_KEY" \-H "Content-Type: application/json" \-d '{"comment": {"text": "you are a clown"},"requestedAttributes": {"TOXICITY": {}, "INSULT": {}},"languages": ["en"],"doNotStore": true}'

1 line changes. The same POST body and the same response, on a different host, with the key as ?key= or a bearer header.

Tested with the request as printed, on every run of the snippet checks. The cURL guide

  • Unchanged
  • The path
  • The request body
  • The response
  • The errors
  • The ?key= parameter

More free tools