<h1 align="center">GLIN PROFANITY</h1>
<p align="center">
<strong>ML-Powered Profanity Detection for the Modern Web</strong>
</p>
<!-- Badges Row 1: Package Info -->
<p align="center">
<a href="https://www.npmjs.com/package/glin-profanity"><img src="https://img.shields.io/npm/v/glin-profanity?style=flat-square&logo=npm&logoColor=white&label=npm" alt="npm version" /></a>
<a href="https://pypi.org/project/glin-profanity/"><img src="https://img.shields.io/pypi/v/glin-profanity?style=flat-square&logo=pypi&logoColor=white&label=pypi" alt="PyPI version" /></a>
<a href="https://www.npmjs.com/package/glin-profanity"><img src="https://img.shields.io/npm/dm/glin-profanity?style=flat-square&logo=npm&logoColor=white&label=npm%20downloads" alt="npm downloads" /></a>
<a href="https://pepy.tech/projects/glin-profanity"><img src="https://img.shields.io/pepy/dt/glin-profanity?style=flat-square&logo=pypi&logoColor=white&label=pypi%20downloads" alt="PyPI downloads" /></a>
</p>
<!-- Badges Row 2: Quality & Status -->
<p align="center">
<a href="https://github.com/GLINCKER/glin-profanity/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/GLINCKER/glin-profanity/ci.yml?style=flat-square&logo=github&label=CI" alt="CI Status" /></a>
<a href="https://bundlephobia.com/package/glin-profanity"><img src="https://img.shields.io/bundlephobia/minzip/glin-profanity?style=flat-square&logo=webpack&logoColor=white&label=bundle%20size" alt="Bundle Size" /></a>
<a href="https://github.com/GLINCKER/glin-profanity/blob/main/LICENSE"><img src="https://img.shields.io/github/license/GLINCKER/glin-profanity?style=flat-square&label=license" alt="License" /></a>
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-Ready-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /></a>
</p>
<!-- Badges Row 3: Community -->
<p align="center">
<a href="https://github.com/GLINCKER/glin-profanity/stargazers"><img src="https://img.shields.io/github/stars/GLINCKER/glin-profanity?style=flat-square&logo=github&label=stars" alt="GitHub Stars" /></a>
<a href="https://github.com/GLINCKER/glin-profanity/network/members"><img src="https://img.shields.io/github/forks/GLINCKER/glin-profanity?style=flat-square&logo=github&label=forks" alt="GitHub Forks" /></a>
<a href="https://github.com/GLINCKER/glin-profanity/issues"><img src="https://img.shields.io/github/issues/GLINCKER/glin-profanity?style=flat-square&logo=github&label=issues" alt="GitHub Issues" /></a>
<a href="https://github.com/GLINCKER/glin-profanity/graphs/contributors"><img src="https://img.shields.io/github/contributors/GLINCKER/glin-profanity?style=flat-square&logo=github&label=contributors" alt="Contributors" /></a>
</p>
<!-- Hero Image -->
<p align="center">
<a href="https://www.glincker.com/tools/glin-profanity" target="_blank">
<img src="./og-image.png" alt="Glin Profanity - ML-Powered Profanity Detection" width="800" />
</a>
</p>
<p align="center">
<a href="https://www.glincker.com/tools/glin-profanity"><img src="https://img.shields.io/badge/Try_Live_Demo-online-blue?style=for-the-badge&logo=vercel&logoColor=white" alt="Live Demo" /></a>
</p>
---
## π¦ Packages
This monorepo maintains the following packages:
| Package | Version | Description |
|---------|---------|-------------|
| [glin-profanity](https://www.npmjs.com/package/glin-profanity) | [](https://www.npmjs.com/package/glin-profanity) | Core profanity filter for JavaScript/TypeScript |
| [glin-profanity](https://pypi.org/project/glin-profanity/) | [](https://pypi.org/project/glin-profanity/) | Core profanity filter for Python |
| [glin-profanity-mcp](https://www.npmjs.com/package/glin-profanity-mcp) | [](https://www.npmjs.com/package/glin-profanity-mcp) | MCP server for AI assistants (Claude, Cursor, etc.) |
| [openclaw-profanity](https://www.npmjs.com/package/openclaw-profanity) | [](https://www.npmjs.com/package/openclaw-profanity) | Plugin for OpenClaw/Moltbot AI agents |
---
## Why Glin Profanity?
Most profanity filters are trivially bypassed. Users type `f*ck`, `sh1t`, or `fΥ½ck` (with Cyrillic characters) and walk right through. Glin Profanity doesn't just check against a word listβit understands evasion tactics.
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GLIN PROFANITY v3 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Input Text βββΊ Unicode βββΊ Leetspeak βββΊ Dictionary βββΊ ML β
β Normalization Detection Matching Checkβ
β (homoglyphs) (f4ckβfuck) (23 langs) (opt) β
β β
β "fΥ½ck" βββΊ "fuck" βββΊ "fuck" βββΊ MATCH βββΊ β β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
## Performance Benchmarks
Tested on Node.js 20, M1 MacBook Pro, single-threaded:
| Operation | Glin Profanity | bad-words | leo-profanity | obscenity |
|-----------|----------------|-----------|---------------|-----------|
| Simple check | **21M ops/sec** | 890K ops/sec | 1.2M ops/sec | 650K ops/sec |
| With leetspeak | **8.5M ops/sec** | N/A | N/A | N/A |
| Multi-language (3) | **18M ops/sec** | N/A | 400K ops/sec | N/A |
| Unicode normalization | **15M ops/sec** | N/A | N/A | N/A |
---
## Feature Comparison
| Feature | Glin Profanity | bad-words | leo-profanity | obscenity |
|---------|----------------|-----------|---------------|-----------|
| Leetspeak detection (`f4ck`, `sh1t`) | Yes | No | No | Partial |
| Unicode homoglyph detection | Yes | No | No | No |
| ML toxicity detection | Yes (TensorFlow.js) | No | No | No |
| Multi-language support | 23 languages | English only | 14 languages | English only |
| Result caching (LRU) | Yes | No | No | No |
| Severity levels | Yes | No | No | No |
| React hook | Yes | No | No | No |
| Python package | Yes | No | No | No |
| TypeScript types | Full | Partial | Partial | Full |
| Bundle size (minified) | 12KB + dictionaries | 8KB | 15KB | 6KB |
| Active maintenance | Yes | Limited | Limited | Limited |
---
## Installation
**JavaScript/TypeScript**
```bash
npm install glin-profanity
```
**Python**
```bash
pip install glin-profanity
```
---
## Quick Start
**JavaScript**
```javascript
import { checkProfanity, Filter } from 'glin-profanity';
// Simple check
const result = checkProfanity("This is f4ck1ng bad", {
detectLeetspeak: true,
languages: ['english']
});
result.containsProfanity // true
result.profaneWords // ['fucking']
// With replacement
const filter = new Filter({
replaceWith: '***',
detectLeetspeak: true
});
filter.checkProfanity("sh1t happens").processedText // "*** happens"
```
**Python**
```python
from glin_profanity import Filter
filter = Filter({"languages": ["english"], "replace_with": "***"})
filter.is_profane("damn this") # True
filter.check_profanity("damn this") # Full result object
```
**React**
```tsx
import { useProfanityChecker } from 'glin-profanity';
function ChatInput() {
const { result, checkText } = useProfanityChecker({
detectLeetspeak: true
});
return (
<input onChange={(e) => checkText(e.target.value)} />
{result?.containsProfanity && <span>Clean up your language</span>}
);
}
```
---
## Architecture
```mermaid
flowchart LR
subgraph Input
A[Raw Text]
end
subgraph Processing
B[Unicode Normalizer]
C[Leetspeak Decoder]
D[Word Tokenizer]
end
subgraph Detection
E[Dictionary Matcher]
F[Fuzzy Matcher]
G[ML Toxicity Model]
end
subgraph Output
H[Result Object]
end
A --> B --> C --> D
D --> E --> H
D --> F --> H
D -.->|Optional| G -.-> H
```
---
## Detection Capabilities
### Leetspeak Detection
```javascript
const filter = new Filter({
detectLeetspeak: true,
leetspeakLevel: 'aggressive' // basic | moderate | aggressive
});
filter.isProfane('f4ck'); // true
filter.isProfane('5h1t'); // true
filter.isProfane('@$$'); // true
filter.isProfane('ph.u" "ck'); // true (aggressive mode)
```
### Unicode Homoglyph Detection
```javascript
const filter = new Filter({ normalizeUnicode: true });
filter.isProfane('fΥ½ck'); // true (Armenian 'Υ½' β 'u')
filter.isProfane('shΡt'); // true (Cyrillic 'Ρ' β 'i')
filter.isProfane('Ζuck'); // true (Latin 'Ζ' β 'f')
```
### ML-Powered Detection
```javascript
import { loadToxicityModel, checkToxicity } from 'glin-profanity/ml';
await loadToxicityModel({ threshold: 0.9 });
const result = await checkToxicity("You're the worst player ever");
// { toxic: true, categories: { toxicity: 0.92, insult: 0.87, ... } }
```
---
## Supported Languages
23 languages with curated dictionaries:
| | | | |
|---|---|---|---|
| Arabic | Chinese | Czech | Danish |
| Dutch | English | Esperanto | Finnish |
| French | German | Hindi | Hungarian |
| Italian | Japanese | Korean | Norwegian |
| Persian | Polish | Portuguese | Russian |
| Spanish | Swedish | Thai | Turkish |
---
## Documentation
| Document | Description |
|----------|-------------|
| [Getting Started](./docs/getting-started.md) | Installation and basic usage |
| [API Reference](./docs/api-reference.md) | Complete API documentation |
| [Framework Examples](./docs/framework-examples.md) | React, Vue, Angular, Express, Next.js |
| [Advanced Features](./docs/advanced-features.md) | Leetspeak, Unicode, ML, caching |
| [ML Guide](./docs/ML-GUIDE.md) | TensorFlow.js integration |
| [Changelog](./CHANGELOG.md) | Version history |
---
## Local Testing Interface
Run the interactive playground locally to test profanity detection:
```bash
# Clone the repo
git clone https://github.com/GLINCKER/glin-profanity.git
cd glin-profanity/packages/js
# Install dependencies
npm install
# Start the local testing server
npm run dev:playground
```
Open **http://localhost:4000** to access the testing interface with:
- Real-time profanity detection
- Toggle leetspeak, Unicode normalization, ML detection
- Multi-language selection
- Visual results with severity indicators
---
## Use Cases
| Application | How Glin Profanity Helps |
|-------------|-------------------------|
| Chat platforms | Real-time message filtering with React hook |
| Gaming | Detect obfuscated profanity in player names/chat |
| Social media | Scale moderation with ML-powered detection |
| Education | Maintain safe learning environments |
| Enterprise | Filter internal communications |
| AI/ML pipelines | Clean training data before model ingestion |
---
## MCP Server for AI Assistants
Glin Profanity includes an MCP (Model Context Protocol) server that enables AI assistants like **Claude Desktop**, **Cursor**, **Windsurf**, and other MCP-compatible tools to use profanity detection as a native tool.
### Quick Setup
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"glin-profanity": {
"command": "npx",
"args": ["-y", "glin-profanity-mcp"]
}
}
}
```
**Cursor** (`.cursor/mcp.json`):
```json
{
"mcpServers": {
"glin-profanity": {
"command": "npx",
"args": ["-y", "glin-profanity-mcp"]
}
}
}
```
### Available Tools (19)
| Tool | Description |
|------|-------------|
| `check_profanity` | Check text for profanity with detailed results |
| `censor_text` | Censor profanity with configurable replacement |
| `analyze_context` | Context-aware analysis with domain whitelists |
| `batch_check` | Check multiple texts in one operation |
| `validate_content` | Content validation with safety scoring (0-100) |
| `detect_obfuscation` | Detect leetspeak and Unicode tricks |
| `get_supported_languages` | List all 24 supported languages |
| `explain_match` | Explain why text was flagged with reasoning |
| `suggest_alternatives` | Suggest clean alternatives for profane content |
| `analyze_corpus` | Analyze up to 500 texts for moderation stats |
| `compare_strictness` | Compare results across strictness levels |
| `create_regex_pattern` | Generate regex patterns for custom detection |
| `track_user_message` | Track user messages for repeat offender detection |
| `get_user_profile` | Get moderation profile for a specific user |
| `get_high_risk_users` | List users with high violation rates |
| `reset_user_profile` | Reset a user's moderation history |
| `stream_check` | Real-time streaming profanity check |
| `stream_batch` | Stream multiple texts with live results |
| `get_stream_stats` | Get streaming session statistics |
**Plus 4 workflow prompts** and **5 reference resources** for guided AI interactions.
### Example Prompts for AI Assistants
```
"Check this user comment for profanity using glin-profanity"
"Validate this blog post content with high strictness"
"Batch check these 50 messages for any inappropriate content"
"Analyze this medical text with the medical domain context"
```
See the full [MCP documentation](./packages/mcp/README.md) for setup instructions and examples.
---
## Roadmap
See our [ROADMAP.md](./ROADMAP.md) for planned features including:
- Streaming support for real-time chat
- OpenAI function calling integration
- Image OCR for profanity in images
- Edge deployment (Cloudflare Workers, Vercel Edge)
- More framework integrations
---
## License
MIT License - free for personal and commercial use.
Enterprise licensing with SLA and support available from [GLINCKER](https://glincker.com).
---
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. We welcome:
- Bug reports and fixes
- New language dictionaries
- Performance improvements
- Documentation updates
---
## Star History
<a href="https://star-history.com/#GLINCKER/glin-profanity&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=GLINCKER/glin-profanity&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=GLINCKER/glin-profanity&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=GLINCKER/glin-profanity&type=Date" />
</picture>
</a>
---
<div align="center">
**[Live Demo](https://www.glincker.com/tools/glin-profanity)** Β· **[NPM](https://www.npmjs.com/package/glin-profanity)** Β· **[PyPI](https://pypi.org/project/glin-profanity/)** Β· **[GitHub](https://github.com/GLINCKER/glin-profanity)**
<br />
<a href="https://github.com/GLINCKER/glin-profanity/stargazers">
<img src="https://img.shields.io/github/stars/GLINCKER/glin-profanity?style=social" alt="Star on GitHub" />
</a>
<br /><br />
<sub>Built by <a href="https://glincker.com">GLINCKER</a> Β· Part of the <a href="https://github.com/GLINCKER">GLINR</a> ecosystem</sub>
</div>