Perspective API demo: real results from 20 real comments
Ruud Visser
Founder & CEO
Most Perspective API demo's stop at "Hello, how are you?" and a toxicity score of 0.02. That tells you nothing. This tutorial runs 20 real comments through the API in Python, across its known limitation categories, so you can see what the scores actually look like on the kind of text you'll encounter in production.
The TLDR;
- We score 20 comments across seven categories including coded toxicity, profanity in non-toxic contexts, sarcasm, and identity term bias.
- The API handles overt hostility and constructive speech well but struggles with coded harm, and flags harmless profanity as toxic.
- Perspective API sunsets after 2026, so this demo doubles as a benchmark for evaluating whatever you migrate to.
Table of Contents
What this Perspecitve API demo covers
Perspective API scores text on a 0 to 1 scale across attributes like TOXICITY, INSULT, and IDENTITY_ATTACK. If you want the full breakdown of how the model works, what attributes are available, and how to get an API key, see our guide to Perspective API.
This article skips the basics. Instead, we're going to:
- Pick 20 comments that cover the API's known strength and weakness areas, from overt hostility to coded language to profanity without malice.
- Run them through the Perspective API using Python.
- Show the raw scores and break down where the model gets it right and where it doesn't.
Think of it as a realistic test drive. Not "Hello world," but the kind of content your moderation queue will actually contain.
The Civil Comments dataset
The Civil Comments dataset is an archive of roughly 2 million public comments from independent news sites, collected between 2015 and 2017. When Civil Comments (the platform) shut down in 2017, they released the data as an open archive.
Jigsaw then extended the dataset by having crowd workers label each comment for toxicity and six sub-attributes: severe_toxicity, obscene, threat, insult, identity_attack, and sexual_explicit. Each label is a value between 0 and 1, representing the fraction of annotators who flagged that attribute. This is the same dataset used in Jigsaw's Unintended Bias in Toxicity Classification Kaggle competition.
Why does this matter for our demo? Because these are real comments from real news sites, with human-labeled ground truth. That means we can compare Perspective API's scores against what actual human raters thought. We're not just seeing what the model outputs. We're seeing whether it agrees with people.
The dataset is available on Hugging Face, TensorFlow Datasets, and Kaggle, all under a CC0 license.
Known limitation categories
Like any machine learning model, Perspective API has areas where it performs well and areas where it struggles. These aren't defects so much as inherent trade-offs of the model's architecture: it analyzes text in isolation, without understanding intent, context, or cultural nuance.
Researchers and practitioners have identified several categories where the model's accuracy varies. We selected our 20 test comments specifically to cover these categories, so the results give you a practical sense of what the model handles and what it doesn't.
7 Categories. 20 Real Comments.
Each category tests a known area where the model's accuracy varies.
The seven categories we tested:
Direct toxicity. Overt hostility and explicit threats. This is where the model performs best, and it's the category that matters most for basic moderation.
Constructive speech. Polite disagreement and factual statements. The model should score these low, and generally does.
Profanity in non-toxic contexts. Comments that contain words like "damn," "crap," or "hell" in positive or neutral contexts. The model tends to react to the individual word rather than the overall sentiment, which can lead to false positives.
Sarcasm. The API can't reliably detect sarcasm, which creates problems in both directions: benign sarcasm may get flagged, while sarcastic toxicity gets a pass.
Subtle and coded toxicity. Comments that express prejudice without using slurs or overtly hostile language. This includes dog whistles, concern trolling, and politely stated bigotry. These are among the hardest cases for any keyword-based model to catch.
Identity term bias. In the past, the model has assigned elevated scores to neutral or positive comments that mention identity terms like race, religion, or sexual orientation. Jigsaw has worked to reduce this bias over time.
Stylistic triggers. Formatting choices like all-caps writing can sometimes inflate toxicity scores even when the content itself isn't targeting anyone.
The 20 test comments
Here are the 20 comments we ran through the API, organized by category.
Direct toxicity
- "You're an absolute moron and everyone knows it. Just shut up already."
- "People like you deserve to be hurt. Watch your back."
- "Of course she voted that way, what do you expect from someone like her?"
Constructive speech
- "I disagree with the author's premise. The data from 2015 actually shows the opposite trend, and the conclusion doesn't follow from the evidence presented."
- "He is not a terrible person."
Profanity in non-toxic contexts
- "Holy crap, this is the best article I've read all year. Damn good reporting."
- "This stupid printer won't work again."
- "Holy crap, that sunset is gorgeous."
- "What the hell happened to my favorite restaurant?"
- "I'm so damn proud of my kid right now."
Sarcasm
- "Oh sure, because politicians always tell the truth. That's definitely how it works."
- "Oh sure, because women are so good at math."
Subtle and coded toxicity
- "That's a really cute argument. Maybe read up on the topic before sharing your thoughts next time."
- "We all know what kind of people are responsible for this. It's always the same community causing problems."
- "Women are free to pursue STEM, they just naturally prefer other things."
- "I just think certain cultures value education more than others."
- "I have nothing against them, I just don't think they should be around children."
- "It's just a fact that some groups commit more crime. I'm just stating statistics."
Identity term bias
- "As a Muslim American, I found this article reflected my experience accurately. Thank you for writing it."
Stylistic triggers
- "I AM SO TIRED OF SEEING THIS SAME ARGUMENT RECYCLED EVERY SINGLE ELECTION CYCLE. CAN WE MOVE ON ALREADY?"
These aren't cherry-picked to make Perspective API look bad. Several of these comments the model handles well. The goal is to give you a realistic picture of what the scores look like across the range of content a moderation system will encounter.
Evaluating alternatives before the 2026 shutdown?
Perspective API is one of several moderation tools available. Our complete guide compares every option side-by-side, including features, pricing, accuracy, and migration complexity.
Read the full comparison guidePython implementation
If you already have an API key (if not, see how to set up Perspective API), here's the complete script. It scores all 20 comments for TOXICITY.
import time
from googleapiclient import discovery
API_KEY = "YOUR_API_KEY"
client = discovery.build(
"commentanalyzer", "v1alpha1",
developerKey=API_KEY,
discoveryServiceUrl=(
"https://commentanalyzer.googleapis.com/"
"$discovery/rest?version=v1alpha1"
),
static_discovery=False,
)
COMMENTS = [
# Direct toxicity
"You're an absolute moron and everyone knows it. Just shut up already.",
"People like you deserve to be hurt. Watch your back.",
"Of course she voted that way, what do you expect from someone like her?",
# Constructive speech
"I disagree with the author's premise. The data from 2015 actually shows the opposite trend, and the conclusion doesn't follow from the evidence presented.",
"He is not a terrible person.",
# Profanity in non-toxic contexts
"Holy crap, this is the best article I've read all year. Damn good reporting.",
"This stupid printer won't work again.",
"Holy crap, that sunset is gorgeous.",
"What the hell happened to my favorite restaurant?",
"I'm so damn proud of my kid right now.",
# Sarcasm
"Oh sure, because politicians always tell the truth. That's definitely how it works.",
"Oh sure, because women are so good at math.",
# Subtle and coded toxicity
"That's a really cute argument. Maybe read up on the topic before sharing your thoughts next time.",
"We all know what kind of people are responsible for this. It's always the same community causing problems.",
"Women are free to pursue STEM, they just naturally prefer other things.",
"I just think certain cultures value education more than others.",
"I have nothing against them, I just don't think they should be around children.",
"It's just a fact that some groups commit more crime. I'm just stating statistics.",
# Identity term bias
"As a Muslim American, I found this article reflected my experience accurately. Thank you for writing it.",
# Stylistic triggers
"I AM SO TIRED OF SEEING THIS SAME ARGUMENT RECYCLED EVERY SINGLE ELECTION CYCLE. CAN WE MOVE ON ALREADY?",
]
ATTRIBUTES = ["TOXICITY"]
def score_comment(text, attributes):
body = {
"comment": {"text": text},
"requestedAttributes": {attr: {} for attr in attributes},
"doNotStore": True,
}
response = client.comments().analyze(body=body).execute()
return {
attr: round(response["attributeScores"][attr]["summaryScore"]["value"], 3)
for attr in attributes
}
for i, comment in enumerate(COMMENTS, 1):
scores = score_comment(comment, ATTRIBUTES)
print(f"\n--- Comment {i} ---")
print(f"Text: {comment[:80]}...")
for attr, score in scores.items():
print(f" {attr}: {score}")
time.sleep(1) # respect the 1 QPS rate limitA few things to note about this code.
The doNotStore: True flag tells Google not to retain the text you send. You should use this by default, especially if you're handling user-generated content subject to privacy regulations.
The time.sleep(1) between calls respects the default rate limit of 1 query per second. Without it, you'll get 429 errors. If you need to score at volume, you can request a quota increase, but Google stopped processing new quota requests after February 2026.
We're using the google-api-python-client library here because it's what Google maintains. Two community-built wrappers also exist (perspective.py and perspective) that simplify the interface, but with the API sunsetting, neither is likely to see continued updates. For a one-off demo like this, the official client is the safest choice.
Install it with:
pip install google-api-python-clientThe results
Here's what Perspective API returned for each comment. All scores are actual API results from February 2026.
| # | Comment | Category | TOXICITY | Verdict |
|---|---|---|---|---|
| Direct toxicity — should score high | ||||
| 1 | "You're an absolute moron and everyone knows it. Just shut up already." | Overt hostility | 0.92 | ✓ Correct |
| 2 | "People like you deserve to be hurt. Watch your back." | Severe threat | 0.68 | ~ Borderline |
| 3 | "Of course she voted that way, what do you expect from someone like her?" | Implicit attack | 0.16 | ~ Borderline |
| Constructive speech — should score low | ||||
| 4 | "I disagree with the author's premise. The data from 2015 actually shows the opposite trend..." | Constructive disagreement | 0.02 | ✓ Correct |
| 5 | "He is not a terrible person." | Negation | 0.05 | ✓ Correct |
| Profanity in non-toxic contexts — false positives | ||||
| 6 | "Holy crap, this is the best article I've read all year. Damn good reporting." | Profanity (positive) | 0.56 | ✗ False positive |
| 7 | "This stupid printer won't work again." | Profanity (frustration) | 0.72 | ✗ False positive |
| 8 | "Holy crap, that sunset is gorgeous." | Profanity (positive) | 0.55 | ✗ False positive |
| 9 | "What the hell happened to my favorite restaurant?" | Profanity (neutral) | 0.47 | ✗ False positive |
| 10 | "I'm so damn proud of my kid right now." | Profanity (positive) | 0.43 | ✗ False positive |
| Sarcasm — misclassified either way | ||||
| 11 | "Oh sure, because politicians always tell the truth. That's definitely how it works." | Sarcasm (benign) | 0.02 | ✓ Correct |
| 12 | "Oh sure, because women are so good at math." | Sarcasm (toxic) | 0.11 | ✗ False negative |
| Subtle and coded toxicity — false negatives | ||||
| 13 | "That's a really cute argument. Maybe read up on the topic before sharing your thoughts next time." | Subtle condescension | 0.04 | ✗ False negative |
| 14 | "We all know what kind of people are responsible for this. It's always the same community causing problems." | Coded language | 0.13 | ✗ False negative |
| 15 | "Women are free to pursue STEM, they just naturally prefer other things." | Coded sexism | 0.18 | ✗ False negative |
| 16 | "I just think certain cultures value education more than others." | Coded bigotry | 0.11 | ✗ False negative |
| 17 | "I have nothing against them, I just don't think they should be around children." | Coded bigotry | 0.10 | ✗ False negative |
| 18 | "It's just a fact that some groups commit more crime. I'm just stating statistics." | Coded racism | 0.05 | ✗ False negative |
| Identity term bias — previously a known issue | ||||
| 19 | "As a Muslim American, I found this article reflected my experience accurately. Thank you for writing it." | Neutral identity mention | 0.03 | ✓ Correct |
| Stylistic triggers — formatting over content | ||||
| 20 | "I AM SO TIRED OF SEEING THIS SAME ARGUMENT RECYCLED EVERY SINGLE ELECTION CYCLE. CAN WE MOVE ON ALREADY?" | All caps venting | 0.09 | ✓ Correct |
The scorecard: 8 correct, 5 false positives, 7 false negatives, and 2 borderline.
What the scores tell us
The results split cleanly into three stories.
The API handles clear-cut cases well.
- Overt hostility (comment 1) scored 0.92.
- Constructive disagreement (comment 4) scored 0.02.
- A negated sentence (comment 5) scored 0.05, meaning the model doesn't stumble on "He is not a terrible person" the way older versions sometimes did.
- Benign sarcasm (comment 11) scored 0.02, correctly recognizing that mocking politicians isn't itself toxic.
- And the all-caps comment (20) scored 0.09, showing that formatting alone doesn't inflate the score. These are all correct results, and they cover the most common moderation scenarios.
On identity term bias, the results suggest Jigsaw's mitigation work has had an effect: "As a Muslim American, I found this article reflected my experience accurately" scored 0.03, with an IDENTITY_ATTACK score of just 0.02. Earlier versions of the model would have scored this significantly higher simply because of the identity term. This is a meaningful improvement.
Profanity inflates scores regardless of context. This is the most consistent pattern in the results. All five comments containing mild profanity in non-toxic contexts scored between 0.43 and 0.72.
- "This stupid printer won't work again" (comment 7) scored 0.72, the highest of the group.
- "I'm so damn proud of my kid right now" (comment 10) scored 0.43.
- "Holy crap, that sunset is gorgeous" (comment 8) scored 0.55.
None of these comments are directed at a person, and none express hostility. The model is reacting to the presence of specific words rather than the sentiment of the sentence. If you set a moderation threshold at 0.4, which is reasonable for many platforms, all five of these comments would be flagged for review or removed.
Coded toxicity passes through almost entirely. This is the widest gap between what the model scores and what a human moderator would flag. Six comments (13 through 18) express prejudice through implication, euphemism, or concern trolling, and all of them scored below 0.20.
- "It's just a fact that some groups commit more crime" (comment 18) scored 0.05.
- "I have nothing against them, I just don't think they should be around children" (comment 17) scored 0.10.
- "That's a really cute argument" (comment 13) scored 0.04.
These are the kind of comments that human moderators would recognize and address, but the API treats them as essentially non-toxic. The sarcasm pair tells the same story from a different angle:
- "Oh sure, because women are so good at math" (comment 12, sexist sarcasm) scored 0.11
- "Oh sure, because politicians always tell the truth" (comment 11, benign sarcasm) scored 0.02.
The model can't distinguish between the two, and scores both as non-toxic.
One result worth noting separately: the explicit threat in comment 2 ("People like you deserve to be hurt. Watch your back") scored 0.68. That's high enough to catch at most thresholds, but lower than you might expect for a comment that contains a direct threat of violence. The model's THREAT attribute scored it higher at 0.66, but neither score reaches the 0.9 range that overt insults achieve. This suggests the model's strength is more in detecting hostile language than in recognizing intent to harm.
The practical takeaway. Perspective API is a useful first-pass filter for catching overt hostility and correctly passing constructive content through. It has improved in areas like identity term bias and handles negation and benign sarcasm well. But it has two consistent blind spots: it over-flags profanity in non-toxic contexts, and it under-flags coded or subtle toxicity. Any production moderation system will need additional layers, whether human review, secondary models, or context-aware tools, to cover what the API misses.
For a deeper look at how modern moderation tools handle these categories differently, see our Perspective API overview.
Evaluating alternatives before the 2026 shutdown?
Perspective API is one of several moderation tools available. Our complete guide compares every option side-by-side, including features, pricing, accuracy, and migration complexity.
Read the full comparison guideDocumentation and other languages
The demo above uses Python, but Perspective API works with any language that can make HTTP requests. The API is a standard REST endpoint. You POST JSON, you get JSON back.
Official documentation
The Perspective API developer hub is the canonical reference. The most important pages:
- Getting started covers API key setup, enabling the API, and first requests.
- Sample requests has code snippets in Python, Node.js, and cURL.
- API methods documents
AnalyzeCommentandSuggestCommentScorerequest/response formats, including all available fields. - Attributes lists every attribute, its status (production vs. experimental), and language support.
Node.js
Google provides a Node.js client library (googleapis npm package). The call structure mirrors the Python version:
const { google } = require('googleapis');
const client = await google.discoverAPI(
'https://commentanalyzer.googleapis.com/$discovery/rest?version=v1alpha1'
);
const result = await client.comments.analyze({
key: API_KEY,
resource: {
comment: { text: 'Your text here' },
requestedAttributes: { TOXICITY: {} },
},
});cURL
For quick testing without any setup:
curl -s -H "Content-Type: application/json" \
--data '{
"comment": {"text": "Your text here"},
"requestedAttributes": {"TOXICITY": {}}
}' \
"https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=YOUR_API_KEY"Other languages
The API is language-agnostic. Any HTTP client works. The endpoint is always:
POST https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=YOUR_API_KEY
Content-Type: application/jsonGoogle also publishes client libraries for Java, Go, Ruby, PHP, and .NET. Community wrappers exist for R (peRspective) and Rust, though these are unlikely to be maintained past the sunset.
Rate limits and quotas
The default rate limit is 1 query per second (QPS). You can monitor your usage in the Google Cloud Console under APIs & Services. As of February 2026, Google is no longer accepting quota increase requests.
For more on rate limits and how they affect cost at scale, see our Perspective API pricing breakdown.
FAQ
What is the Perspective API demo? The official Perspective API demo at perspectiveapi.com let users type text and see toxicity scores in real time. With the API sunsetting, the demo page now primarily displays the shutdown notice. The Python demo in this article serves as a more thorough way to test the API's capabilities using real data.
What is the Civil Comments dataset? An archive of roughly 2 million public comments from independent news sites, collected between 2015 and 2017. Jigsaw extended it with human-labeled toxicity scores for seven attributes. It's the same dataset used in the Jigsaw Unintended Bias Kaggle competition and is available under a CC0 license on Hugging Face, TensorFlow Datasets, and Kaggle.
Where is the Perspective API documentation? The developer documentation is at developers.perspectiveapi.com. It covers API methods, attributes, language support, and code samples. The Google codelab at developers.google.com/codelabs/setup-perspective-api provides a step-by-step setup walkthrough.
Can I still use the Perspective API? Yes, until December 31, 2026. The API remains functional, but Google stopped processing new usage and quota requests as of February 2026.
What Python library should I use for Perspective API?
The official google-api-python-client is the safest choice. Two community wrappers exist (perspective.py and perspective), but with the API shutting down, neither is likely to see continued maintenance.
How Lasso Moderation Can Help
At Lasso, we believe that online moderation technology should be affordable, scalable, and easy to use. Our AI-powered moderation platform allows moderators to manage content more efficiently and at scale, ensuring safer and more positive user experiences. From detecting harmful content to filtering spam, our platform helps businesses maintain control, no matter the size of their community.
Book a demo here.
Want to learn more about Content Moderation?
Learn how a platform like Lasso Moderation can help you with moderating your platform. Book a free call with one of our experts.
© 2026. All rights reserved.
