# Profanity Detector - Wordlist Filter, Catches f\*ck & f4ck (`eliai/profanity-detector`) Actor

Screen up to 1,000 texts per run against a tiered profanity wordlist with obfuscation heuristics (leet, spacing, partial masks) — severity, exact positions, masked cleanedText, Scunthorpe-guarded boundaries. A filter, NOT an AI moderation system. $0.0004 per text, junk entries never charged.

- **URL**: https://apify.com/eliai/profanity-detector.md
- **Developed by:** [Broke to Built](https://apify.com/eliai) (community)
- **Categories:** Developer tools, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.32 / 1,000 screened texts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Profanity Detector — Wordlist Filter with Obfuscation Heuristics

Screen text for profanity — including the obfuscated kind (`f*ck`, `sh!t`, `f u c k`, `f4ck`, `fuuuck`) — and get back severity-tiered matches with exact positions plus a masked `cleanedText`. Up to 1,000 texts per run, online, by API, or as an agent tool via Apify MCP.

**What this is — stated plainly:** a **wordlist + pattern-heuristic filter**, not an AI moderation system. It matches a curated multi-tier term list with leetspeak/spacing/partial-masking tolerance. It does **not** understand context, sarcasm, harassment without swear words, hate speech phrased politely, or threats — and it makes **no safety guarantees**. Use it as the cheap first-pass layer (UGC pre-filters, username/comment hygiene, log sweeps); decisions that affect user safety need human review or a context-aware moderation system on top.

### What you get

- **isClean** — the bottom-line flag per text
- **matches** — each hit: base `word`, the exact `matched` span, `severity` (1-3 tiered) + label, `start`/`end` positions
- **cleanedText** — your text with matched spans masked (`maskChar`, default `*`), everything else untouched
- **severity / severityScore** — the strongest tier found
- **Obfuscation-tolerant, boundary-anchored**: catches leet/spacing/censored variants while word boundaries prevent the classic Scunthorpe-problem false positives (class, assassin, Scunthorpe pass clean — asserted by our release test)
- **Fail-soft**: a non-string entry never fails the run — `{ok: false, error}`, **never charged**.

### Input

```json
{ "texts": ["have a wonderful day!", "this is total bullsh1t"], "maskChar": "*" }
```

Or a single string via `text`.

### Output (real run)

```json
{
  "ok": true,
  "text": "what the f*ck is this sh!t",
  "isClean": false,
  "matchCount": 2,
  "matches": [
    { "word": "fuck", "matched": "f*ck", "severity": 2, "severityLabel": "strong", "start": 9, "end": 13 },
    { "word": "shit", "matched": "sh!t", "severity": 2, "severityLabel": "strong", "start": 22, "end": 26 }
  ],
  "severity": "strong",
  "cleanedText": "what the **** is this ****"
}
```

### Pricing

**$0.0004 per text screened.** No start fee. Non-string entries are never charged. A 100,000-comment sweep costs $40 across runs.

Measured against store incumbents (2026-08-07): nibble/profanity-content-filter charges $0.002 per result, maximedupre/profanity-checker $0.00025 per text (cheaper than us, 2 users — but without positional matches/severity tiers per its listing).

### Honest limits

- **Wordlist-bound**: only terms on the list (and their obfuscations) are caught. New slang, other languages, and creative insults that avoid listed terms pass clean.
- **No context**: "this is shit" and a quoted lyric score the same; a vile message with no listed words scores clean. This is inherent to wordlist filtering — we will not pretend otherwise.
- Not a compliance or brand-safety certification of any kind.
- English-focused list; leet handling covers Latin-script obfuscation only.

### FAQ

**Is this a content moderation system?**
No. It is the fast, deterministic, cheap layer that catches listed profanity including obfuscated spellings. Real moderation needs context models and humans; many pipelines use this filter first and escalate only flagged or ambiguous content.

**How does it avoid the Scunthorpe problem?**
Matches are word-boundary anchored — a listed term embedded inside a longer word (classic, assassin, Scunthorpe) does not trip. Our automated release test asserts this on every deploy.

**What do the severity tiers mean?**
The built-in list is tiered mild(1)/strong(2)/severe(3); `severity` reports the strongest tier found so you can apply different policies (e.g. mask tier 1-2, reject tier 3).

**Can I use cleanedText directly?**
Yes — masked spans keep their length and spacing, everything unmatched is byte-identical to your input.

**Why did some rows come back `ok: false`?**
Those entries were not strings. Recorded, never charged.

### Use from code or AI agents

```bash
curl -s "https://api.apify.com/v2/acts/EliAI~profanity-detector/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"texts": ["comment one", "c0mment tw0 with sh!t in it"]}'
```

Agents: connect [Apify MCP](https://mcp.apify.com) and call the `EliAI/profanity-detector` tool.

- **Capability:** wordlist + obfuscation-heuristic profanity screening with severity, positions and masked text — NOT context-aware moderation, no safety guarantees
- **Required input:** `text` (string) or `texts` (array)
- **Returns:** one record per text; `isClean` + `matches` + `cleanedText` summarize it
- **Bounded:** 1,000 texts per run; failures isolate per text
- **Side effects:** none (texts never leave the run)

# Actor input Schema

## `text` (type: `string`):

A single piece of text to scan for profanity. Handles leetspeak (f4ck), spacing/punctuation obfuscation (s h i t, f.u.c.k) and avoids the Scunthorpe problem via word boundaries.

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

Multiple texts to scan in one run. Each is analyzed independently and produces its own result row.

## `maskChar` (type: `string`):

Character used to mask detected profanity in cleanedText. Defaults to \*.

## `maxTexts` (type: `integer`):

Safety cap on how many texts to process in one run.

## Actor input object example

```json
{
  "text": "what the f*ck is this sh!t, you absolute m0ron",
  "texts": [
    "have a wonderful day!",
    "this is total bullsh1t",
    "I love Scunthorpe and my classmates"
  ],
  "maskChar": "*",
  "maxTexts": 50
}
```

# Actor output Schema

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

Every item this run produced, as JSON.

## `resultsCsv` (type: `string`):

The same items as a spreadsheet-ready CSV.

# 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 = {
    "text": "what the f*ck is this sh!t, you absolute m0ron",
    "texts": [
        "have a wonderful day!",
        "this is total bullsh1t",
        "I love Scunthorpe and my classmates"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eliai/profanity-detector").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 = {
    "text": "what the f*ck is this sh!t, you absolute m0ron",
    "texts": [
        "have a wonderful day!",
        "this is total bullsh1t",
        "I love Scunthorpe and my classmates",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("eliai/profanity-detector").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 '{
  "text": "what the f*ck is this sh!t, you absolute m0ron",
  "texts": [
    "have a wonderful day!",
    "this is total bullsh1t",
    "I love Scunthorpe and my classmates"
  ]
}' |
apify call eliai/profanity-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eliai/profanity-detector"
        }
    }
}

```

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/LAR1eTBFhDvQKz6XX/builds/LFWBh5LCTNWalO2lJ/openapi.json
