# Perspective API Alternative - Toxicity Detection API & MCP (`koyourmoon/perspective-api-alternative`) Actor

Drop-in replacement for Google Perspective API (shutting down Dec 31, 2026). Same request/response format for TOXICITY, SEVERE_TOXICITY, INSULT, PROFANITY, THREAT and IDENTITY_ATTACK. Also a batch API and an MCP server for AI agents.

- **URL**: https://apify.com/koyourmoon/perspective-api-alternative.md
- **Developed by:** [KOYOURMOON](https://apify.com/koyourmoon) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 text units

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Perspective API Alternative: Toxicity Detection API & MCP Server

**Google stops the Perspective API on December 31, 2026. Google gives no migration support.** This Actor is a direct replacement. It uses the same request format, the same response format and the same attribute names. To move to this Actor, change the URL only.

- **Perspective-compatible endpoint:** `POST /v1alpha1/comments:analyze`
- **Six attributes:** `TOXICITY`, `SEVERE_TOXICITY`, `INSULT`, `PROFANITY`, `THREAT`, `IDENTITY_ATTACK`
- **Batch endpoint:** send a maximum of 100 comments in one call. A Console run accepts a maximum of 10,000 comments.
- **MCP server:** AI agents (Claude, Cursor and other agents) can examine text before they publish it.
- **No LLM:** the model is fast and deterministic. The same text always gets the same score.
- **No text storage through the API:** the server keeps API and MCP requests in memory only. It does not store or log them. A Console run saves the results to your own dataset.
- **Long comments:** the model divides a long text into chunks that overlap. Thus, it examines the end of the text too. In a very long, polite text, one insult can get a score below 0.5. For documents, use `spanAnnotations` or a lower threshold.

### Change to this Actor in 1 minute

```diff
- https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key=GOOGLE_API_KEY
+ https://koyourmoon--perspective-api-alternative.apify.actor/v1alpha1/comments:analyze?token=APIFY_TOKEN
```

Do not change the request body:

```python
import requests

URL = "https://koyourmoon--perspective-api-alternative.apify.actor/v1alpha1/comments:analyze"
body = {
    "comment": {"text": "What kind of idiot name is foo?"},
    "languages": ["en"],
    "requestedAttributes": {"TOXICITY": {}, "INSULT": {}},
}
r = requests.post(URL, json=body, headers={"Authorization": "Bearer <APIFY_TOKEN>"})
print(r.json()["attributeScores"]["TOXICITY"]["summaryScore"]["value"])  # 0.93
```

The response has the same format as the Perspective response:

```json
{
  "attributeScores": {
    "TOXICITY": {
      "spanScores": [{"begin": 0, "end": 31, "score": {"value": 0.926868, "type": "PROBABILITY"}}],
      "summaryScore": {"value": 0.926868, "type": "PROBABILITY"}
    }
  },
  "languages": ["en"],
  "detectedLanguages": ["en"]
}
```

The endpoint accepts these request options: `spanAnnotations` (scores for each sentence), `scoreThreshold`, `clientToken`, `languages` and `doNotStore`.

The endpoint also accepts attribute names with the `_EXPERIMENTAL` suffix (for example, `TOXICITY_EXPERIMENTAL`). These names are aliases.

Error responses use the Perspective `errorType` values: `ATTRIBUTE_NOT_SUPPORTED`, `LANGUAGE_NOT_SUPPORTED_BY_ATTRIBUTE`, `COMMENT_EMPTY` and `COMMENT_TOO_LONG`.

### Coral by Vox Media (Talk): change two settings

Coral sends each new comment to the Perspective API. You can send these comments to this Actor. Coral keeps the query of the endpoint URL. Thus, you can put your Apify token in the endpoint.

1. In the Coral admin, open **Configure** > **Moderation**.
2. Find the settings of the toxic comment filter (Perspective).
3. In the endpoint field, enter `https://koyourmoon--perspective-api-alternative.apify.actor/v1alpha1?token=<APIFY_TOKEN>`.
4. In the key field, enter any text. The Actor does not use this key.
5. Keep your model (`TOXICITY` or `SEVERE_TOXICITY`) and your threshold.
6. Save the settings.

In the Coral GraphQL API, these fields are `endpoint` and `key` of the Perspective integration.

CAUTION: Increase the Coral timeout before you use this endpoint. The default Coral timeout for Perspective calls is 800 ms (environment variable `PERSPECTIVE_TIMEOUT`). If a call takes more time, Coral publishes the comment without a toxicity score. We recommend `PERSPECTIVE_TIMEOUT=3000`. After an idle period of 60 seconds, the first call can take 10 to 30 seconds (cold start). Thus, on a site with little traffic, Coral can publish some comments without a score.

The Actor also accepts the Perspective feedback calls (`comments:suggestscore`). It does not store them, and it does not charge for them.

Use the same method for other clients that let you change the Perspective endpoint.

### Batch endpoint

```bash
curl -X POST "https://koyourmoon--perspective-api-alternative.apify.actor/v1/analyze" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"texts": ["Great post!", "You are an idiot"], "attributes": ["TOXICITY","INSULT"], "threshold": 0.5}'
```

```json
{"results": [
  {"text": "Great post!", "scores": {"TOXICITY": 0.0006, "INSULT": 0.0002}, "flagged": false, "billed_units": 1},
  {"text": "You are an idiot", "scores": {"TOXICITY": 0.98, "INSULT": 0.95}, "flagged": true, "billed_units": 1}
]}
```

### MCP server for AI agents

Add this text to the configuration of your MCP client:

```json
{
  "mcpServers": {
    "toxicity": {
      "url": "https://koyourmoon--perspective-api-alternative.apify.actor/mcp",
      "headers": {"Authorization": "Bearer <APIFY_TOKEN>"}
    }
  }
}
```

The server has one tool: `analyze_toxicity(texts, attributes?, threshold?)`. Use this tool to examine comments, replies or LLM output before your agent publishes them.

### Runs without code

1. Open the Actor in the Console.
2. Paste a maximum of 10,000 texts. Put one text on each line.
3. Start the run.
4. Download the scores as CSV, JSON or Excel.

### Prices

| Event | Price |
|---|---|
| Text unit (each started 1,000 characters of a comment) | **$0.50 for 1,000 units** ($0.0005 for each unit) |
| Actor start | $0.002 for each GB of memory (about $0.004 for each start at the default 2 GB) |

**Most comments have less than 1,000 characters. Thus, most comments cost 1 unit ($0.0005).** A longer comment costs more units. For example, a comment with 2,500 characters costs 3 units. Azure Content Moderator uses the same method: it charges for each 1,000 characters.

Batch results and Console results show `billed_units`. There is no subscription and no minimum. You do not pay for requests that are not valid.

- **Console runs and API runs:** you pay only the prices in the table.
- **Standby API and MCP:** while the server operates, Apify charges the platform usage of the server to your account. Apify does this for all Standby Actors.
- The server stops after 60 seconds without requests. Thus, a small quantity of requests costs very little.
- For a constant flow of requests, send the comments in batches of a maximum of 100 with `POST /v1/analyze`.

### Comparison with Perspective

| | Perspective API | This Actor |
|---|---|---|
| Availability | Stops on December 31, 2026 | Available |
| Request and response format | v1alpha1 | Same |
| Attributes | 6 production + experimental | 6 production (+ `_EXPERIMENTAL` aliases) |
| Languages | Many | **English** (more languages in the plan) |
| Text storage | Optional | The API and MCP do not store text |

**About the scores.** The model is the open-source [Detoxify](https://github.com/unitaryai/detoxify) "original" model. Jigsaw, the team that made Perspective, released the Toxic Comment dataset. Detoxify learned from this dataset.

The scores tell almost the same thing as the Perspective scores. But the values are not the same. If you use fixed thresholds, compare them with a sample of your own data after you change to this Actor.

### Frequently asked questions

**Does this Actor have a relation with Google or Jigsaw?** No. This Actor is an independent, compatible service.

**Can I use it for text that is not in English?** Version 1 supports English only. The endpoint returns `LANGUAGE_NOT_SUPPORTED_BY_ATTRIBUTE` in these conditions:

- The request has a different value in `languages`.
- The request has no `languages` value, and the text is clearly in a non-Latin script (for example, Korean, Cyrillic, Chinese or Arabic).

Perspective returns the same error for languages that it does not support. Thus, you do not pay for a score that you cannot use. The batch endpoint gives scores for these texts, but it adds a `warning` field to the result.

**How fast is it?** When the server operates, a short comment takes tens of milliseconds. After a period without requests, the first request starts the server. This cold start usually takes 10 to 30 seconds. Set a client timeout of a minimum of 60 seconds. Standby mode adds servers automatically when the load increases.

**What is the maximum length of a comment?** The maximum length is 20,480 bytes. Perspective has the same limit.

# Actor input Schema

## `texts` (type: `array`):

1 to 10,000 English texts (comments, posts, reviews, chat messages or LLM output). Put one text in each item. The Actor ignores empty items. Each started 1,000 characters of a text is 1 billed text unit. For calls in real time, use the Standby HTTP endpoint or the MCP server of this Actor.

## `attributes` (type: `array`):

Scores to return. Select one or more of TOXICITY, SEVERE_TOXICITY, INSULT, PROFANITY, THREAT and IDENTITY_ATTACK. If this field is empty, you get all six.

## `threshold` (type: `string`):

A number from 0 to 1, as text (for example "0.5"). If the TOXICITY score is equal to or more than this value, flagged is true.

## Actor input object example

```json
{
  "texts": [
    "Thanks for sharing, this was really helpful!",
    "You are an idiot and nobody wants you here."
  ],
  "threshold": "0.5"
}
```

# Actor output Schema

## `results` (type: `string`):

One item per text: the text, flagged (TOXICITY >= threshold) and scores for TOXICITY, SEVERE_TOXICITY, INSULT, PROFANITY, THREAT, IDENTITY_ATTACK.

## `api` (type: `string`):

Base URL of the running web server. Endpoints: POST /v1alpha1/comments:analyze (Perspective-compatible), POST /v1/analyze (batch), POST /mcp (MCP server).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "texts": [
        "Thanks for sharing, this was really helpful!",
        "You are an idiot and nobody wants you here."
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("koyourmoon/perspective-api-alternative").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "texts": [
        "Thanks for sharing, this was really helpful!",
        "You are an idiot and nobody wants you here.",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("koyourmoon/perspective-api-alternative").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "texts": [
    "Thanks for sharing, this was really helpful!",
    "You are an idiot and nobody wants you here."
  ]
}' |
apify call koyourmoon/perspective-api-alternative --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,koyourmoon/perspective-api-alternative"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oNuVI2iemruytqeFM/builds/AzDReCxmwf7MDnrJ5/openapi.json
