Skip to content

coffee-and-fun/google-profanity-words

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

87 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

alt text

โ˜• Google Profanity Words

A fun and developer-friendly profanity detection library brought to you by Coffee & Fun LLC โ˜•๐ŸŽ‰ Built and maintained with love by Robert James Gabriel ๐Ÿ’ปโœจ

npm version Stars


๐Ÿš€ What's This?

Google Profanity Words is a Node.js library that helps you detect and filter out naughty language (in multiple languages!) from your apps or content. Whether you're building a chat app, a comment section, a game, or a comment moderator โ€” this one's your profanity-slaying sidekick.

Made by devs for devs. Maintained by Robert at Coffee & Fun โ˜•โค๏ธ


โœจ Features

  • ๐ŸŒ Multilingual โ€” English, Spanish, French, Irish, Arabic, and Chinese out of the box
  • โšก Fast & tiny โ€” zero runtime dependencies, O(1) lookups with Set
  • ๐Ÿงช Battle-tested โ€” 200+ Jest tests across every language
  • ๐Ÿ”’ Secure by default โ€” no polynomial regex, ships with provenance
  • ๐Ÿ“ TypeScript ready โ€” types included, no @types install needed
  • ๐ŸŽฏ Framework-friendly โ€” works with Express, Fastify, Koa, Next.js, Discord.js, you name it

๐Ÿ“ฆ Install Me

npm install @coffeeandfun/google-profanity-words

Requires Node.js 16+.


โšก Quickstart Guide

import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

// Default is English
const profanity = new ProfanityEngine();

// Espaรฑol? You got it.
const profanityES = new ProfanityEngine({ language: 'es' });

// Check a single word
const isBad = await profanity.search('hell');

// Or check a full sentence
const hasCurses = await profanity.hasCurseWords('This is a test sentence');

// Or grab the actual bad words
const found = await profanity.getCurseWords('oh hell and damn');

console.log(isBad, hasCurses, found);
// โ†’ true, false, ['hell', 'damn']

That's the whole idea. Everything below is detail. โœจ


๐Ÿง  What a Returned Object Looks Like

Every check method is async and returns a Promise. Here's what you'll actually see back:

await profanity.hasCurseWords('oh hell no');
// โ†’ true

await profanity.hasCurseWords('have a lovely day');
// โ†’ false

await profanity.getCurseWords('hell, damn, and hell again');
// โ†’ ['hell', 'damn']                 // unique, lowercase

await profanity.getCurseWords('a perfectly fine sentence');
// โ†’ []                               // empty array, never null

await profanity.search('HELL');
// โ†’ true                             // case-insensitive

await profanity.search('hello');
// โ†’ false

await profanity.all();
// โ†’ ['2 girls 1 cup', '2g1c', '4r5e', /* โ€ฆ962 total */]

๐Ÿ” API Reference

๐Ÿ› ๏ธ new ProfanityEngine(options?)

Create a new profanity detector engine!

const profanity = new ProfanityEngine(); // Defaults to English
const spanishProfanity = new ProfanityEngine({ language: 'es' });

Options

Option Type Default What it does
language string 'en' ISO code matching a file in data/. Falls back to English.
testMode boolean false When true, suppresses console.warn output (great in tests).

๐Ÿ”Ž search(word)

Check a single word to see if it's naughty.

await profanity.search('heck');   // โ†’ false
await profanity.search('hell');   // โ†’ true
await profanity.search('HELL');   // โ†’ true (case-insensitive)
await profanity.search('  hell '); // โ†’ true (trimmed for you)
await profanity.search('');       // โ†’ false
await profanity.search(null);     // โ†’ false (handles bad input)

๐Ÿ’ฌ hasCurseWords(sentence)

Check a full sentence or phrase for profanity.

await profanity.hasCurseWords('You silly goose');        // โ†’ false
await profanity.hasCurseWords('oh hell no');             // โ†’ true
await profanity.hasCurseWords('(hell)!');                // โ†’ true (punctuation is handled)
await profanity.hasCurseWords('This is hellhole land');  // โ†’ false (whole-word match)

๐Ÿ“‹ getCurseWords(sentence)

Get the actual bad words that showed up (unique, lowercase).

await profanity.getCurseWords('hell and damn and hell again');
// โ†’ ['hell', 'damn']

await profanity.getCurseWords('a clean message');
// โ†’ []

Great for logging moderation events or showing users exactly what tripped the filter.


๐Ÿ“œ all()

Get the full list of bad words in the current language.

const badWords = await profanity.all();
console.log(badWords.length); // โ†’ 962 (for English)
console.log(badWords[0]);     // โ†’ '2 girls 1 cup'

The returned array is a copy โ€” mutating it won't affect the engine.


๐Ÿ”„ reset()

Clears the in-memory cache. Next call re-reads the data file. Useful in tests or if you hot-swap the data file.

profanity.reset();

๐ŸŒ Supported Languages

Code Language Entries (approx.)
en English ๐Ÿ‡ฌ๐Ÿ‡ง (default) 962
es Spanish ๐Ÿ‡ช๐Ÿ‡ธ 564
fr French ๐Ÿ‡ซ๐Ÿ‡ท 23
ga Irish ๐Ÿ‡ฎ๐Ÿ‡ช 15
ar Arabic 23
zh Chinese ๐Ÿ‡จ๐Ÿ‡ณ 30

If you pass a language code that doesn't exist, the engine gracefully falls back to English and prints a warning (unless testMode: true).


๐Ÿ’ก Real Talk: Edge Cases

  • Empty strings? We gotchu. Returns false / []. ๐Ÿ‘Œ
  • null, undefined, numbers, objects? No crashes โ€” returns false / [].
  • Case-insensitive by default (Hell, HELL, hell all match).
  • Handles punctuation: hell!, (hell), "hell", hell. โ€” all detected.
  • Whole-word matching: hellhole does not trigger on hell.
  • Works with Unicode (Spanish ยฟ/ยก, Chinese characters, Arabic, etc.) thanks to Intl.Segmenter.

๐Ÿงช Testing with Jest

We've got testing covered like whipped cream on a latte โ˜•๐ŸŽ‚

# Run the full suite
npm test

# Run a single language's tests
npm run en
npm run es
npm run engine

# Or use Jest directly
npx jest --watch
npx jest --coverage
npx jest path/to/file.test.js

Tests live in __tests__/ and run against the real word-list files โ€” no mocking, no surprises. ๐ŸŽฏ


๐Ÿ”€ Example Use Cases

โœ… Filter User Input

import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

const profanity = new ProfanityEngine();

async function cleanInput(input) {
  if (await profanity.hasCurseWords(input)) {
    return 'โš ๏ธ Whoa there! Language, please.';
  }
  return input;
}

๐ŸŒ Multi-Language Setup

const en = new ProfanityEngine({ language: 'en' });
const es = new ProfanityEngine({ language: 'es' });

const [englishHit, spanishHit] = await Promise.all([
  en.hasCurseWords('oh hell no'),
  es.hasCurseWords('ยกquรฉ mierda!'),
]);

console.log(englishHit, spanishHit); // โ†’ true, true

๐Ÿšฆ Express Middleware

Block profane comments at the API boundary.

import express from 'express';
import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

const app = express();
const profanity = new ProfanityEngine();

app.use(express.json());

app.post('/comments', async (req, res) => {
  const text = req.body?.text ?? '';
  if (await profanity.hasCurseWords(text)) {
    return res.status(400).json({
      error: 'Please keep it friendly ๐Ÿ’›',
    });
  }
  res.json({ ok: true, comment: text });
});

app.listen(3000);

โšก Fastify

import Fastify from 'fastify';
import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

const app = Fastify();
const profanity = new ProfanityEngine();

app.post('/chat', async (request, reply) => {
  const { message } = request.body;
  if (await profanity.hasCurseWords(message)) {
    reply.code(400);
    return { error: 'Please watch your language ๐Ÿ˜…' };
  }
  return { ok: true, message };
});

await app.listen({ port: 3000 });

๐Ÿงญ Koa

import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

const app = new Koa();
const profanity = new ProfanityEngine();

app.use(bodyParser());
app.use(async (ctx) => {
  const { text = '' } = ctx.request.body || {};
  if (await profanity.hasCurseWords(text)) {
    ctx.status = 400;
    ctx.body = { error: 'Language, please ๐Ÿ™ˆ' };
    return;
  }
  ctx.body = { ok: true };
});

app.listen(3000);

๐Ÿ”บ Next.js API Route (App Router)

app/api/moderate/route.js:

import { NextResponse } from 'next/server';
import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

const profanity = new ProfanityEngine();

export async function POST(request) {
  const { text } = await request.json();
  const hasBadWords = await profanity.hasCurseWords(text);
  return NextResponse.json({ clean: !hasBadWords });
}

๐ŸŽฎ Discord.js Bot

Delete messages with profanity and warn the user.

import { Client, GatewayIntentBits } from 'discord.js';
import { ProfanityEngine } from '@coffeeandfun/google-profanity-words';

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

const profanity = new ProfanityEngine();

client.on('messageCreate', async (message) => {
  if (message.author.bot) return;

  if (await profanity.hasCurseWords(message.content)) {
    await message.delete();
    await message.channel.send(
      `${message.author}, please keep the channel friendly ๐Ÿ’›`
    );
  }
});

client.login(process.env.DISCORD_TOKEN);

๐ŸŽญ Replace / Censor Matched Words

Swap found words with asterisks.

async function censor(text) {
  const bad = await profanity.getCurseWords(text);
  let result = text;
  for (const word of bad) {
    const mask = '*'.repeat(word.length);
    result = result.replaceAll(new RegExp(`\\b${word}\\b`, 'gi'), mask);
  }
  return result;
}

await censor('what the hell, damn it');
// โ†’ 'what the ****, **** it'

๐Ÿ“Š Count Profanity

async function countBad(text) {
  const words = await profanity.getCurseWords(text);
  return {
    count: words.length,
    words,
    hasProfanity: words.length > 0,
  };
}

await countBad('hell and damn and hell again');
// โ†’ { count: 2, words: ['hell', 'damn'], hasProfanity: true }

๐Ÿ“ฆ Batch Processing

Check a whole array of strings in parallel.

const messages = [
  'hello world',
  'oh hell no',
  'have a great day',
  'damn it',
];

const results = await Promise.all(
  messages.map(async (msg) => ({
    message: msg,
    clean: !(await profanity.hasCurseWords(msg)),
  }))
);

console.log(results);
// [
//   { message: 'hello world',       clean: true  },
//   { message: 'oh hell no',        clean: false },
//   { message: 'have a great day',  clean: true  },
//   { message: 'damn it',           clean: false },
// ]

๐Ÿงฉ TypeScript

Types ship with the package โ€” just import.

import {
  ProfanityEngine,
  ProfanityEngineOptions,
} from '@coffeeandfun/google-profanity-words';

const options: ProfanityEngineOptions = { language: 'en', testMode: true };
const profanity = new ProfanityEngine(options);

const hit: boolean = await profanity.hasCurseWords('oh hell no');
const words: string[] = await profanity.getCurseWords('oh hell no');

๐ŸŒ Want to Contribute?

We love open source buddies ๐Ÿ’›

Add a New Language

  1. Fork it ๐Ÿด
  2. Add a file to /data/ named like de.txt for German (ISO 639-1 code)
  3. Fill it with one profane word per line, lowercase
  4. Add a test file under __tests__/ following spanish.test.js as a template
  5. Push & open a pull request! ๐Ÿš€

๐Ÿ™Œ Who Made This?

Built by Robert James Gabriel and the good people at Coffee & Fun LLC. We make dev tools with accessibility, coffee, and good vibes in mind.

Wanna support? Send a coffee our way or just spread the word! โ˜•๐Ÿš€


๐Ÿ” Security

Found a vulnerability? Please report it privately โ€” see SECURITY.md. ๐Ÿ™


๐Ÿงก License

MIT โ€“ because sharing is caring.


๐Ÿ’ฌ Support & Community


Made with โ˜•, code, and a sprinkle of magic at Coffee & Fun LLC ๐Ÿ’–

๐Ÿค– AI Usage

Claude AI was used to help with this README and with adding extra Jest tests.

About

Full list of bad words and top swear words banned by Google.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors