A Hindi and Indian-language profanity filter for JavaScript and TypeScript. Detects abuse in Devanagari, Bengali, Gurmukhi, Gujarati, Odia, Tamil, Telugu, Kannada and Malayalam — and in romanized Hinglish, Banglish, Punglish, Tanglish, Tenglish, Kanglish, Manglish and Odlish — including spellings it has never seen. Zero dependencies, fully offline.
⚠️ Offensive content. This package ships word lists of real slurs in nine Indic scripts and in romanized form, undersrc/data/, so that software can detect them. This README and the docs use masked spellings only.
npm install remove-profanity
import { createMatcher } from 'remove-profanity';
import { hindi } from 'remove-profanity/data/hi';
import { english } from 'remove-profanity/data/en';
const matcher = createMatcher({ packs: [hindi, english] });
matcher.isClean('hello world'); // true
matcher.isClean('kya bh#sdike yaar'); // false
matcher.censor('kya bh#sdike yaar'); // 'kya ******** yaar'
matcher.censor('what the f*ck', { keepFirst: true }); // 'what the f***'
matcher.scan('what the f*ck').maxSeverity; // 3Full API, every option, and the exact shape scan() returns:
docs/usage.md.
- Romanized Indic text has no fixed spelling, and a word list cannot
contain every variant. A phonetic skeleton tier collapses aspiration, vowel
length and retroflex/dental distinctions, so one entry catches
behench*d≡bahanch*d≡bhainch*d— including spellings nobody wrote down. - Evasion-resistant by construction. Leetspeak, Cyrillic and Greek
homoglyphs, fullwidth and math alphanumerics, zero-width injection, letter
stretching, interior masks (
f*ck,b***h), spelled-out words (s.h.i.*) and chunk splits (as sh o*e) all resolve against the dictionary. - Unicode done right for Indian languages. Word boundaries come from
Unicode properties, never ASCII
\b(which is broken for Devanagari). Censoring works in grapheme clusters, so Indic matches mask cleanly instead of leaving orphaned matras. Each script gets its own orthography rules. - Whole-token matching, so the Scunthorpe problem is solved generally.
Every pattern must span a complete token, checked against the original text.
Scunthorpe,Penistone,Middlesex,cocktail,assassinandshiitakeare clean — andPenistoneis in no allowlist of ours, while a leading rival flags it.
Per-word severity 0–4 and categories (sexual, gendered, slur,
casteist, religious, …) let you filter at the level your product needs.
Six libraries, each in its maximum claimed configuration, against a 97-axis battery this project owns and publishes. English is the only language all six claim, so it is the only like-for-like comparison — and it is the one below.
| Library | Evasion caught /88 | False positives /486 | 20k clean words |
|---|---|---|---|
| remove-profanity | 81 (92%) | 3 | 1.99 ms |
| obscenity | 61 (69%) | 10 | 11.53 ms |
| allprofanity | 57 (65%) | 28 | 3.80 ms |
| bad-words | 39 (44%) | 3 | 8.67 ms |
| @2toad/profanity | 38 (43%) | 14 | 2.23 ms |
| leo-profanity | 18 (20%) | 4 | 0.66 ms |
The Indic scorecards (720/864 on ten Indian languages), the full seven-column speed grid, the 1.77M-word dictionary sweep, and every gap listed by name are in docs/benchmarks.md. Every figure traces to benchmark/results.txt.
Eleven packs, 338 lemmas, imported separately so you only pay for what you
use. Each subpath is remove-profanity/data/<code>:
Hindi + Hinglish hi |
Bengali + Banglish bn |
Punjabi + Punglish pa |
English en |
Marathi mr |
Gujarati gu |
Tamil + Tanglish ta |
Telugu + Tenglish te |
Odia + Odlish or |
Kannada + Kanglish kn |
Malayalam + Manglish ml |
Every pack is self-sufficient: importing one language gives you full coverage of it, including the romanizations it shares with another pack. Load only the languages your users write in — extra packs cost startup time and can add cross-language false positives. Guidance: docs/usage.md.
Want your language supported? Native-speaker contributions are the only way several Indian languages will ever get quality coverage. The recipe, with the false-positive traps that actually bite, is in docs/language-packs.md.
| docs/usage.md | Install, imports, createMatcher, isClean, scan, censor, every option and default, the returned shape, per-language subpath imports, pack selection. |
| docs/matching.md | The four tiers, the fold pipeline, what it catches and what it deliberately does not, the allowlist mechanism, severity and categories. |
| docs/benchmarks.md | Every benchmark table in full, with the unflattering readings kept in. |
| docs/language-packs.md | Adding a language pack, step by step. |
| docs/mcp.md | The bundled MCP server (remove-profanity-mcp): four read-only tools so an agent can moderate text without writing code. Still zero dependencies. |
| llms.txt | Terse machine-readable reference. Hand this to your coding agent and it will wire the package up correctly first time. |
| SPEC.md | Per-module contract. |
| benchmark/METHODOLOGY.md | How the battery is built and what it refuses to do. |
Built for products where users type Indian languages on an English keyboard: Hinglish abuse detection in chat and comments, romanized Indic text moderation in reviews and user-generated content, community and gaming platforms, and support inboxes. Works in Node 18+, in bundlers, and offline — no API calls, no network, no telemetry, no model to download.
MIT.