Perspective API shuts down after 31 December 2026. Keep the same request.
Last updated:
⏳ 87 days left — the old API shuts down December 31, 2026.
Yes: Google's Perspective API stops serving requests after December 31, 2026, and Google is not offering migration support (perspectiveapi.com). To keep existing comments:analyze code working, point it at a wire-compatible replacement such as our Perspective drop-in on Apify: it takes the same request and returns the same attributeScores JSON for $1 per 1,000 comments, and you change only the host and the key.
Google's own words: the API "will no longer be in service after 2026", usage and quota requests were "addressed until February 2026", and "we will not be offering direct migration support". The scores in our replacement come from open models of the same family (Detoxify), so they are close to Perspective's but not identical. See How the scores compare. Planning the switch step by step? Use the Perspective shutdown migration checklist.
What changes on January 1, 2027
After December 31, 2026 the service is gone, so these stop working:
- Every request to
https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze. That covers REST, Google'sgoogleapiclient, theperspective-api-clientnpm package, R'speRspectiveand similar. comments:suggestscoreand anything else on that host.- Plugins that hard-code the host, such as the Discourse plugin and many Discord moderation bots.
- Research and benchmark code that uses Perspective's TOXICITY score as a metric.
New keys and quota increases already ended in February 2026, so you cannot get a new Google key to buy time.
The minimal migration: host and key only
The new endpoint is the Actor's Standby URL, https://dropin-apis--perspective-compat.apify.actor. Authenticate with your Apify API token, either as Authorization: Bearer … or as ?token=…. A leftover Google key= parameter is accepted and ignored. The request body and the response are unchanged.
curl
- curl -s -X POST "https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=$GOOGLE_API_KEY" \
+ curl -s -X POST "https://dropin-apis--perspective-compat.apify.actor/v1alpha1/comments:analyze" \
+ -H "Authorization: Bearer $APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"comment":{"text":"You are an idiot"},"requestedAttributes":{"TOXICITY":{}}}'Python (requests)
- URL = "https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=" + GOOGLE_API_KEY
- HEADERS = {}
+ URL = "https://dropin-apis--perspective-compat.apify.actor/v1alpha1/comments:analyze"
+ HEADERS = {"Authorization": "Bearer " + os.environ["APIFY_TOKEN"]}
r = requests.post(URL, headers=HEADERS, json={"comment": {"text": text}, "requestedAttributes": {"TOXICITY": {}}})
score = r.json()["attributeScores"]["TOXICITY"]["summaryScore"]["value"]Node.js (fetch)
- const url = `https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=${process.env.GOOGLE_API_KEY}`;
- const headers = { 'Content-Type': 'application/json' };
+ const url = 'https://dropin-apis--perspective-compat.apify.actor/v1alpha1/comments:analyze';
+ const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.APIFY_TOKEN}` };
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ comment: { text }, requestedAttributes: { TOXICITY: {} } }) });
const score = (await res.json()).attributeScores.TOXICITY.summaryScore.value;Response (real output from our test run):
{
"attributeScores": {
"TOXICITY": {
"spanScores": [{ "begin": 0, "end": 16, "score": { "value": 0.99683121, "type": "PROBABILITY" } }],
"summaryScore": { "value": 0.99683121, "type": "PROBABILITY" }
}
},
"languages": ["en"],
"detectedLanguages": ["en"]
}Library-specific notes
Python: Google's own google-api-python-client
Keep your Perspective quickstart code. Only the build() call changes: point discoveryServiceUrl at the Actor and pass your Apify token as credentials.
import os
from googleapiclient import discovery
from google.oauth2.credentials import Credentials
BASE = "https://dropin-apis--perspective-compat.apify.actor"
APIFY_TOKEN = os.environ["APIFY_TOKEN"]
client = discovery.build(
"commentanalyzer", "v1alpha1",
credentials=Credentials(APIFY_TOKEN), # was: developerKey=GOOGLE_API_KEY
discoveryServiceUrl=BASE + "/$discovery/rest?version={apiVersion}&token=" + APIFY_TOKEN,
static_discovery=False,
)
response = client.comments().analyze(body={
"comment": {"text": "friendly greetings from python"},
"requestedAttributes": {"TOXICITY": {}},
}).execute()
print(response["attributeScores"]["TOXICITY"]["summaryScore"]["value"]) # 0.01015937Node.js: the perspective-api-client npm package
The package hard-codes Google's URL and bundles its own copy of axios, so an interceptor on your app's axios has no effect. Attach the redirect to the axios instance the library actually loads, once at startup:
const libAxios = require(require.resolve('axios', { paths: [require.resolve('perspective-api-client')] }));
const BASE = 'https://dropin-apis--perspective-compat.apify.actor';
libAxios.interceptors.request.use((cfg) => {
if (cfg.url && cfg.url.startsWith('https://commentanalyzer.googleapis.com')) {
cfg.url = cfg.url.replace('https://commentanalyzer.googleapis.com', BASE);
cfg.headers.Authorization = `Bearer ${process.env.APIFY_TOKEN}`;
}
return cfg;
});
// unchanged application code:
const Perspective = require('perspective-api-client');
const perspective = new Perspective({ apiKey: 'unused-but-required-by-the-library' });
perspective.analyze('You are a complete moron', { attributes: ['toxicity', 'insult'] })
.then((r) => console.log(r.attributeScores.TOXICITY.summaryScore.value)); // 0.99700852Discourse (discourse-perspective-api)
The plugin keeps the API key as a site setting, but the host is the constant GOOGLE_API_DOMAIN = "https://commentanalyzer.googleapis.com" in lib/discourse_perspective.rb. In a fork:
- change that constant to your Standby URL;
- append
token=<APIFY_TOKEN>to the request query.
The plugin's models (TOXICITY, SEVERE_TOXICITY) and thresholds work as before. We have not run this inside a live Discourse instance. The request and response format is what we tested.
Your options compared
| Option | Same request and JSON as Perspective? | Attributes | Price | Notes |
|---|---|---|---|---|
| Perspective drop-in on Apify (this page) | Yes: change host and key | TOXICITY, SEVERE_TOXICITY, INSULT, THREAT, IDENTITY_ATTACK, PROFANITY, SEXUALLY_EXPLICIT (en) | $1 per 1,000 comments | Open Detoxify models; scores close, not identical. 7 languages. Nothing stored |
| Self-host Detoxify | No: Python library, your own API wrapper | toxicity, severe_toxicity, obscene, threat, insult, identity_attack, sexual_explicit | Free (Apache-2.0) + your servers | The same model family we run; you operate it |
OpenAI moderation (omni-moderation-latest) | No: different endpoint, categories and response | harassment, hate, violence, sexual, self-harm and more | Free with an OpenAI account | Policy categories, not Perspective attributes; thresholds must be re-tuned |
| Azure AI Content Safety | No: different endpoint and severity scale | Hate, Sexual, Violence, SelfHarm (severity levels) | Free tier 5,000 text records/month; paid per Azure pricing | Azure account and resource required |
If you can rewrite the integration and re-tune thresholds, any of the alternatives is reasonable. The drop-in is for code, stored scores and dashboards that depend on Perspective's exact request and response.
Supported attributes and languages
| Attribute | en | es fr it pt ru tr | Notes |
|---|---|---|---|
| TOXICITY, SEVERE_TOXICITY, INSULT, THREAT, IDENTITY_ATTACK | ✅ | ✅ | |
| PROFANITY | ✅ | ✅ | Approximated from the model's "obscene" output |
| SEXUALLY_EXPLICIT | ✅ | — | English only, as in Perspective |
*_EXPERIMENTAL aliases | ✅ | ✅ | Served by the matching base attribute and returned under the name you requested |
| FLIRTATION, the NYT models, bridging attributes | ❌ | ❌ | Returns Perspective's own LANGUAGE_NOT_SUPPORTED_BY_ATTRIBUTE error |
- The language is detected automatically when you leave out
languages. Other languages get Perspective's standard "does not support request languages" error, so your existing fallback code keeps working. spanAnnotations,scoreThreshold,clientTokenand snake_case field names are supported.- The limit is 20 KB of text per comment.
How the scores compare
The scores come from Detoxify, open models trained on the same Jigsaw/Civil Comments data family that Perspective came from. They run as quantized ONNX on CPU inside the Actor: unbiased-toxic-roberta for English and multilingual-toxic-xlm-roberta for the other six languages.
- Clear cases agree. In our tests, abusive text scored 0.99+ and polite text scored under 0.02.
- Borderline comments can differ from Perspective by a noticeable margin. We have not run a side-by-side calibration against the live Perspective API.
- If you auto-hide comments at a high threshold (0.85–0.9), you will probably see similar behavior. If you act at low thresholds, run a sample of your own comments through the Actor's batch mode first and re-tune.
Pricing
$1 per 1,000 analyzed comments, pay per event.
- Failed requests (4xx) are not charged.
- There is no subscription.
- You can cap spending per run on Apify. When you reach your limit, the API answers
429 RESOURCE_EXHAUSTED.
FAQ
Is the Perspective API shutting down?
Yes. Google's Perspective API site says the API will no longer be in service after 2026 (after December 31, 2026). Usage and quota requests were only handled until February 2026.
Does Google offer a migration path for Perspective API?
No. Google says it will not offer direct migration support. It points to other tools inspired by Perspective, but none of them uses the same API.
What is the best Perspective API replacement?
If you want to keep your code unchanged, use a wire-compatible drop-in that accepts POST /v1alpha1/comments:analyze and returns the same attributeScores JSON; this page's Actor does that for $1 per 1,000 comments. If you can rewrite your integration, OpenAI's free moderation endpoint, Azure AI Content Safety or a self-hosted Detoxify model also work, with different categories and scores.
How do I migrate from Perspective API?
Change the host from commentanalyzer.googleapis.com to the Actor's Standby URL and replace ?key=GOOGLE_KEY with your Apify token (Authorization: Bearer …). The request body and the response JSON stay the same. Then re-check your thresholds on a sample of real comments.
Will my toxicity thresholds still work?
For clear-cut text, yes: abusive comments still score above 0.99 and polite ones below 0.02 in our tests. Borderline comments can score differently, so if you act at low thresholds, test a sample first.
Is this affiliated with Google?
No. It is an independent service that implements the public commentanalyzer v1alpha1 interface.
Do you store comments?
No. Text is scored in memory and discarded.
How fast is it?
About 10–30 ms per comment on a warm instance. After about 5 minutes without traffic the instance sleeps, and the next request waits a few seconds while it starts.
Get started
Open the Actor on the Apify Store, then copy its Standby URL and your token: Perspective API drop-in on Apify.