CLEANER
SAFER
COMMUNITIES
—
Open source · v2.5.0

terlik.js

Profanity filtering
that catches the tricks.

A fast, extensible and multilingual profanity detection engine for developers.

// not a naive blacklist
// a normalization + pattern engine
Try it live ↓ $ npm i terlik.js
Turkish-firstBuilt for real language
4 languagesTR · EN · ES · DE
Zero deps~14 KB gzip
<1ms checksFast & efficient
Runs anywhereNode · Browser · Bun · Deno · Edge
Live playground

Try to sneak one past it.

This is the real library, running in your browser inside a Web Worker. Type anything, pick a preset, switch languages and modes. Nothing leaves your machine.

input.txt 0 chars

Evasion tricks — click to load

Whitelist traps — should stay clean

terlik.clean(text) getMatches · clean
WARMING UP
0 matches–
…
normalized–
compiling Turkish patterns in a worker (one-time, first call only)…
#general — live moderation 0 filtered
server.ts
import { Terlik } from "terlik.js";

// one instance, warmed up at boot
const terlik = new Terlik();
terlik.containsProfanity("warmup");

io.on("connection", (socket) => {
  socket.on("message", (text) => {
    // <1ms per message after warmup
    io.emit("message", terlik.clean(text));
  });
});
How it works

Ten passes of normalization, then the pattern engine.

Every trick people use gets undone before matching. The engine is language-agnostic — each language ships only data: a char map, a leet map, char classes and a dictionary.

01

Strip invisible chars

sZWiZWk→sik
02

NFKD decompose

sik→sik
03

Strip diacritics

sîk→sik
04

Locale lowercase

SİK→sik
05

Cyrillic → Latin

аmk→amk
06

Char folding

şık→sik
07

Number words

s2k→sikik
08

Leet decode

$1k→sik
09

Separator removal

s.i.k→sik
10

Repeat collapse

siiiiik→sik
pattern match + suffix engine→whitelist filter→result// 83 Turkish suffixes, up to 2 chained: sik + tir + ler
normalize() →
…
Benchmarks

High precision. No false alarms.

In chat systems a false positive costs more than a miss — blocking “class” or “Amsterdam” erodes trust. terlik.js keeps a deliberately narrow dictionary and lets the engine do the expansion.

F1 score — 1,281-sample adversarial English corpus default settings
terlik.js
81.0%
obscenity
42.9%
bad-words
32.2%
allprofanity
28.7%
terlik.js: 100.0% precision · 0.0% false-positive rate. On the curated 290-sample subset it scores 100% F1. Corpus includes zalgo, zero-width, homoglyph and reversed-text attacks. Reproduce with pnpm bench:compare.
0Kclean msgs / sec
0Kstrict mode msgs / sec
0%F1 · TR balanced
0tests
0+TR forms from 147 roots
~0msconstruction (lazy compile)
Get started

Three lines to a cleaner chat.

ESM + CJS, full TypeScript types, per-language sub-path imports when you want the smallest possible bundle.

$ npm install terlik.js $ pnpm add terlik.js $ yarn add terlik.js
  • Three modes: strict · balanced · loose (fuzzy)
  • Mask styles: stars · partial · replace
  • Filter by severity and category
  • addWords / removeWords / extendDictionary
  • ReDoS-safe patterns with a timeout safety net
Node 20+BrowsersBunDenoCloudflare WorkersEdge
import { Terlik } from "terlik.js";

const terlik = new Terlik();              // Turkish by default

terlik.containsProfanity("siktir git");   // true
terlik.clean("siktir git burdan");        // "****** git burdan"
terlik.containsProfanity("Amsterdam");    // false — whitelisted

const en = new Terlik({ language: "en" });
en.clean("what the phuck");               // "what the *****"
Community ports

Same engine, other stacks.

// cleaner conversations for a better internet

Give your chat
a terlik.

MIT licensed · zero dependencies · contributions & new language packs welcome