Perspective API alternative — comments:analyze drop-in avatar

Perspective API alternative — comments:analyze drop-in

Pricing

from $1.00 / 1,000 comment analyzeds

Go to Apify Store
Perspective API alternative — comments:analyze drop-in

Perspective API alternative — comments:analyze drop-in

Perspective API alternative that accepts POST /v1alpha1/comments:analyze and returns the same attributeScores JSON. Google shuts the original down after 31 Dec 2026 with no migration. Change the host. $1 per 1,000 comments.

Pricing

from $1.00 / 1,000 comment analyzeds

Rating

0.0

(0)

Developer

drop-in apis

drop-in apis

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

3 hours ago

Last modified

Share

Perspective API alternative for commentanalyzer.googleapis.com: this Actor accepts POST /v1alpha1/comments:analyze and returns the same attributeScores JSON (TOXICITY, INSULT, THREAT, PROFANITY and the rest), so existing code keeps working after Google shuts Perspective down after 31 December 2026 (Google's notice).

At a glance: $1.00 per 1,000 analyzed comments (errors are free) · about 10–30 ms of model time per comment on a warm Standby instance · no quota forms · scores are independent Detoxify probabilities, not Google's. Try it with no code: click Start with the prefilled input (batch mode), or call the Standby comments:analyze endpoint.

Last updated: 2026-10-02 · Full migration guide: https://alidaram99.github.io/api-alternatives/perspective-api-alternative/

Errors use the same Google error envelope, so your moderation code, thresholds and error handling keep working. You change the host and add your Apify token.

  • ✅ Same request and response shape as Perspective v1alpha1. Google's own Python client (googleapiclient.discovery.build) works against it.
  • ✅ TOXICITY, SEVERE_TOXICITY, INSULT, PROFANITY, THREAT, IDENTITY_ATTACK, SEXUALLY_EXPLICIT
  • ✅ English plus Spanish, French, Italian, Portuguese, Russian and Turkish, with automatic language detection
  • ✅ About 10–30 ms of model time per comment; no rate limits or quota forms
  • ✅ $1 per 1,000 analyzed comments. You pay only for successful analyses; errors are free.
  • 🔒 We never store comment text. Scoring runs inside the Actor's container, and no third-party AI API is called.

Who is this for?

  • Forums, comment sections and community platforms (Discourse, Coral, custom CMS) that pre-screen comments with Perspective
  • Discord, Twitch and Telegram moderation bots that call comments:analyze
  • Researchers and LLM-evaluation pipelines (RealToxicityPrompts-style benchmarks) that need a TOXICITY score after Perspective is gone
  • Anyone who tuned thresholds such as "flag above 0.85 TOXICITY" and doesn't want to rewrite code for a different API

Migrate in one minute

Your endpoint is the Actor's Standby URL. You'll find it on the Actor's Standby tab, for example https://<username>--perspective-compat.apify.actor. Authenticate with your Apify API token, either as ?token=… or as an Authorization: Bearer … header. The key= parameter is accepted and ignored.

curl / any HTTP client

# Before
curl -X POST "https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=$GOOGLE_KEY" \
-H 'Content-Type: application/json' \
-d '{"comment":{"text":"You are an idiot"},"requestedAttributes":{"TOXICITY":{},"INSULT":{}},"languages":["en"]}'
# After: same body, same response
curl -s -X POST "https://<username>--perspective-compat.apify.actor/v1alpha1/comments:analyze?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"comment":{"text":"You are an idiot"},"requestedAttributes":{"TOXICITY":{},"INSULT":{}},"languages":["en"]}'

Response (exact shape Perspective returns):

{
"attributeScores": {
"TOXICITY": {
"spanScores": [{ "begin": 0, "end": 16, "score": { "value": 0.9963, "type": "PROBABILITY" } }],
"summaryScore": { "value": 0.9963, "type": "PROBABILITY" }
}
},
"languages": ["en"],
"detectedLanguages": ["en"]
}

Python: Google's own client (google-api-python-client)

Keep your Perspective quickstart code. 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://<username>--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: fetch

const BASE = 'https://<username>--perspective-compat.apify.actor';
const res = await fetch(`${BASE}/v1alpha1/comments:analyze`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.APIFY_TOKEN}` },
body: JSON.stringify({ comment: { text: 'You are an idiot' }, requestedAttributes: { TOXICITY: {} } }),
});
const data = await res.json();
console.log(data.attributeScores.TOXICITY.summaryScore.value); // 0.99683121

Node.js: perspective-api-client (npm)

The package hard-codes Google's URL and bundles its own copy of axios (0.18.x), so an interceptor on your app's axios never sees its requests. Attach the redirect to the axios instance the library itself loads, once at startup:

const libAxios = require(require.resolve('axios', { paths: [require.resolve('perspective-api-client')] }));
const BASE = 'https://<username>--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 plugin)

The plugin hard-codes GOOGLE_API_DOMAIN = "https://commentanalyzer.googleapis.com" in lib/discourse_perspective.rb. In your fork, change that constant to your Standby URL and append token=<APIFY_TOKEN> to the query it sends. The rest of the plugin, including the TOXICITY and SEVERE_TOXICITY models and the thresholds, works unchanged.

Supported attributes and languages

Attributeenes fr it pt ru trNotes
TOXICITY✅✅
SEVERE_TOXICITY✅✅
INSULT✅✅
PROFANITY✅✅Approximated from the Detoxify "obscene" head
THREAT✅✅
IDENTITY_ATTACK✅✅
SEXUALLY_EXPLICIT✅—English only, as in Perspective
*_EXPERIMENTAL aliases (e.g. TOXICITY_EXPERIMENTAL)✅✅Served by the matching base attribute and returned under the name you requested
FLIRTATION and the NYT models (ATTACK_ON_AUTHOR, INCOHERENT, INFLAMMATORY, LIKELY_TO_REJECT, OBSCENE, SPAM, UNSUBSTANTIAL), bridging attributes❌❌Returns Perspective's own LANGUAGE_NOT_SUPPORTED_BY_ATTRIBUTE error, which existing clients already handle

If you leave out languages, the language is detected automatically. For any other language you get Perspective's standard error, so your existing fallback logic keeps working:

{"error":{"code":400,"message":"Attribute TOXICITY does not support request languages: fi","status":"INVALID_ARGUMENT",
"details":[{"@type":"type.googleapis.com/google.commentanalyzer.v1alpha1.Error","errorType":"LANGUAGE_NOT_SUPPORTED_BY_ATTRIBUTE",
"languageNotSupportedByAttributeError":{"detectedLanguages":["fi"],"attribute":"TOXICITY"}}]}}

Request fields supported

comment.text, requestedAttributes{…: {scoreType, scoreThreshold}}, languages, spanAnnotations (per-sentence spanScores), clientToken (echoed back), doNotStore, sessionId and communityId. The last three are accepted, and nothing is ever stored. context is accepted and ignored. Both camelCase and snake_case work. The maximum is 20 KB of text per comment, the same as Perspective.

Only scoreType: "PROBABILITY" is supported. Other score types return Perspective's "Requested score type … is not supported" error. comments:suggestscore is accepted and acknowledged, but feedback is not stored.

How it compares

OptionSame comments:analyze request and JSON?PriceNotes
This ActorYes: change the host, add an Apify token$1 per 1,000 commentsOpen Detoxify models; scores are close to Perspective's, not identical
Google Perspective APIIt is the originalFreeStops after 31 Dec 2026; no migration tool
OpenAI Moderation APINo: different request, categories and scoresFree (rate-limited)Rewrite parsing and re-tune thresholds
Azure AI Content SafetyNo: severity levels for Hate/Sexual/SelfHarm/ViolencePaid per text recordDifferent URL, auth and JSON
Other APIs marketed as "Perspective alternatives"Usually a different request/response shapeVariesCheck whether your client code has to change

Pricing

$1.00 per 1,000 analyzed comments (pay-per-event, comment-analyzed). Failed requests (4xx errors) are not charged. Apify also adds its standard small per-start fee to each run. In Standby mode you don't pay for idle time. Set a maximum total charge on the run, and once it is reached the API returns 429 RESOURCE_EXHAUSTED.

For comparison: Perspective was free until it shut down. Paid moderation APIs charge from about $0.38 to $2 per 1,000 texts, and none of them use Perspective's request and response format.

Batch mode (no code)

Prefer a spreadsheet? Run the Actor normally with a list of comments. You get one dataset row per comment, with a column per attribute, and can export it as CSV, Excel or JSON.

{ "comments": ["Thanks, this helped!", "You are an idiot."], "requestedAttributes": ["TOXICITY", "INSULT"] }

Accuracy: read before switching thresholds

The scores come from the open-source Detoxify models, which were trained on the same Jigsaw/Civil Comments data that Perspective was built on. They run as quantized ONNX:

  • English: unbiased-toxic-roberta
  • Other languages: multilingual-toxic-xlm-roberta

Scores are well calibrated probabilities, but they are not identical to Perspective's numbers. Clear-cut toxic text scores 0.95–0.99 and benign text below 0.05, while borderline comments can differ by ±0.1–0.2. If you used a high cut-off such as 0.85–0.9, it usually carries over. If you auto-reject at a low threshold, re-check it on a sample of your own comments first. Batch mode makes that easy.

Comments longer than about 512 tokens are scored sentence by sentence in chunks. The summary is the highest chunk score, so a toxic sentence inside a long post is still caught.

Latency and cold start

On a warm instance, the model scores a comment in about 10–30 ms, and the API usually answers in under 100 ms including network. After about 5 minutes without requests the instance sleeps, and the next request waits a few seconds while it starts. The first non-English request after a start also loads the multilingual model, which takes about 1–2 s. If you moderate live chat synchronously, send a request every few minutes to keep the instance warm, or score asynchronously.

Limits

  • Up to 20 KiB of UTF-8 text per comment; longer text returns Perspective's COMMENT_TOO_LONG-style error. Text beyond about 512 tokens is scored in chunks and the summary is the highest chunk score.
  • Only scoreType: "PROBABILITY" is supported; other score types return Perspective's own "not supported" error.
  • comments:suggestscore is accepted and acknowledged, but feedback is not stored or used for training.
  • Scores can differ from Perspective's by roughly ±0.1–0.2 on borderline comments; high cut-offs usually carry over, low auto-reject thresholds should be re-checked on your own data.
  • After about 5 minutes without requests the Standby instance sleeps, and the next request waits a few seconds (the first non-English request also loads the multilingual model, about 1–2 s).

FAQ

What is a Perspective API alternative that keeps comments:analyze?

This Actor. It serves the same POST /v1alpha1/comments:analyze path and returns the same JSON; you authenticate with an Apify token instead of a Google key. $1 per 1,000 successful calls.

When does Google shut down the Perspective API?

After 31 December 2026. Google's own page says there is no migration path: https://perspectiveapi.com/

Are the toxicity scores identical to Google's?

No. They come from open Detoxify models trained on the same Jigsaw/Civil Comments data family. Clear cases agree; borderline comments can differ. Re-check any threshold you tuned on Google's numbers, for example with batch mode.

Which languages does the toxicity API support?

English, Spanish, French, Italian, Portuguese, Russian and Turkish. SEXUALLY_EXPLICIT is English only, as in Perspective. Other languages return Perspective's own LANGUAGE_NOT_SUPPORTED_BY_ATTRIBUTE error.

Does it work with google-api-python-client?

Yes. Set discoveryServiceUrl to this Actor's Standby URL and pass your Apify token as credentials (see the Python example above). The request body stays the same.

How much does the Perspective API alternative cost?

$0.001 per analyzed comment ($1 per 1,000). Errors are not charged. Apify also charges its standard Actor start event ($0.00005), shown on the Pricing tab.

Can I keep using ?key=?

The key parameter is accepted and ignored. Authentication happens through your Apify token (?token= or an Authorization: Bearer header).

Do you store my comments?

No. Text is scored in memory and discarded. The Standby API writes nothing to disk. In batch mode, results are saved only to your own run's dataset.

Is there a rate limit?

There is no Perspective-style QPS quota. Throughput scales with Apify Standby instances.

Is this affiliated with Google or Jigsaw?

No. It is an independent, compatible implementation of the public commentanalyzer v1alpha1 interface. If something doesn't match Perspective's behaviour, open an issue on this Actor's Issues tab with the request body.