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:

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

diff
- 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)

diff
- 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)

diff
- 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):

json
{
  "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.

python
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.01015937

Node.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:

js
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.99700852

Discourse (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:

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

OptionSame request and JSON as Perspective?AttributesPriceNotes
Perspective drop-in on Apify (this page)Yes: change host and keyTOXICITY, SEVERE_TOXICITY, INSULT, THREAT, IDENTITY_ATTACK, PROFANITY, SEXUALLY_EXPLICIT (en)$1 per 1,000 commentsOpen Detoxify models; scores close, not identical. 7 languages. Nothing stored
Self-host DetoxifyNo: Python library, your own API wrappertoxicity, severe_toxicity, obscene, threat, insult, identity_attack, sexual_explicitFree (Apache-2.0) + your serversThe same model family we run; you operate it
OpenAI moderation (omni-moderation-latest)No: different endpoint, categories and responseharassment, hate, violence, sexual, self-harm and moreFree with an OpenAI accountPolicy categories, not Perspective attributes; thresholds must be re-tuned
Azure AI Content SafetyNo: different endpoint and severity scaleHate, Sexual, Violence, SelfHarm (severity levels)Free tier 5,000 text records/month; paid per Azure pricingAzure 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

Attributeenes fr it pt ru trNotes
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

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.

Pricing

$1 per 1,000 analyzed comments, pay per event.

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.