List of profanity words, with a filter tester
Here's a free list of 333 English profanity words and phrases you can reuse under CC BY 4.0. View it, copy it or download it as TXT, JSON or CSV from the bar under the tester. But a list is only half a filter. What it catches depends on how it's matched, so paste a real chat message into the tester and see what gets masked and what gets through. It matches whole words, the same way TalkJS's forbidden word list does.
How other users see it
2 words masked
- bullshit
- ass
Reading your result
The tester masks a word only when the whole word or phrase is on the list, whatever its capitalization. In the example message, "bullshit" and "ass" are masked. "Classic" and "assessment" stay as they are, even though both contain "ass".
That's why TalkJS matches whole words. A filter that matches letters inside words masks innocent words too, a mistake known as the Scunthorpe problem, after the English town whose name contains a swear word.
Whole-word matching has blind spots, though. Three kinds of words get through:
- Other forms of a listed word. "ass" is on the list and "asses" isn't, so "asses" stays visible. Add the forms your users actually write.
- Spaced or swapped letters, like "s h i t" or "sh1t". Spaced spellings work as list entries: add "s h i t" as a phrase. Swapped letters need a custom suppression pattern, a regular expression such as
/sh[i1!]t/i, which masks "sh1t" and "sh!t". - Entries that start or end with an accented letter or a symbol, like "café" or "a$$". These don't match as standalone words, even when they're on the list. The next section explains why, and a custom pattern handles these too.
How the matching works
The tester runs the same steps as a TalkJS chat. We copied them from our own source code:
- Split the list into lines and trim the spaces around each one.
- Lowercase every line, and skip empty lines and lines that start with
#. - Escape characters that mean something in a regular expression, like
.or*, so each entry is matched as plain text. - Join all entries into one pattern,
\b(entry1|entry2|...)\b, with the flagsg(every match) andi(ignore case). - Replace each match with the replacement text and keep the rest of the message.
Two details of that pattern decide what your list catches:
- Word edges.
\bmarks the edge of a word. In a JavaScript pattern like this one, only the letters A to Z, the digits and the underscore count as word characters. Spaces, punctuation, hyphens and apostrophes count as edges, so the "shit" in "bull-shit" and in "Shit!" is masked. An entry that starts or ends with any other character, like "café", doesn't match as a standalone word. Write a custom pattern for those. - Overlapping phrases. When one entry is the start of a longer one, like "fuck" and "fuck buttons", the entry listed first wins. If "fuck" comes first, the phrase shows up as "(hidden information) buttons". Our list puts every phrase before the shorter entries it starts with. Single words that share a start, like "ass" and "asshole", are masked in full whatever the order.
Where the list comes from
The list is the English file of the List of Dirty, Naughty, Obscene, and Otherwise Bad Words (LDNOOBW). Shutterstock made it to keep bad words out of its search suggestions and recommendations, and published it under the CC BY 4.0 license. The English file has 403 entries and last changed on July 13, 2020.
We made three changes. We removed a middle-finger emoji, because a whole-word filter can never match it. We removed 69 entries that would mask normal messages: everyday words and phrases like "sucks", "tied up" and "snowballing", and medical terms like "rectum". And we moved longer phrases ahead of the words they start with. That leaves 333 entries, 108 of them phrases of two or more words.
Two other free lists show up in the same searches:
| List | Entries | License | What to know |
|---|---|---|---|
| LDNOOBW English (this page) | 403 (we use 333) | CC BY 4.0 | Built to filter search suggestions. Last changed July 2020. |
| Carnegie Mellon bad-words.txt | 1,383 | None stated | From 2009. Includes words like "black", "jesus" and "muslim". |
| profane-words | 2,725 | WTFPL | Compiled from several lists. Its README warns of false positives. |
A longer list isn't a better one. Every extra entry is one more way to mask a normal message, so start with a short list and add words when your users need them.
Add the list to your TalkJS chat
TalkJS includes a forbidden word list on every plan, and you set it up without code:
- Download the TXT file. Its license lines start with
#, so TalkJS ignores them. - In the TalkJS dashboard, open the Chat UI tab and go to Mask unwanted content.
- Choose a mode. The default is No suppression, and the word list field appears once you pick another mode. Masked words show as "(hidden information)" in each user's language, or as your own replacement text.
- Paste the list under Forbidden words, one word or phrase per line. The TXT file is 3,678 characters and the field takes 100,000, so there's room for the forms you add.
We suggest Selective suppression. Other users see the replacement text, but senders don't see their own words masked, which makes the filter harder to work around. These settings are per role, so a marketplace can give buyers and sellers different lists.
If the list masks a word your users need, delete that line. Suppression exceptions work too: TalkJS lets a match through when an exception pattern matches it, including matches from the word list. The content suppression guide covers custom patterns and exceptions, and chat moderation shows the rest of TalkJS's moderation tools.
FAQs
Yes. The list is licensed CC BY 4.0, which allows any use, including commercial use, as long as you credit the source, link to the license and say what you changed. The TXT and JSON downloads include those lines.
No. TalkJS replaces each masked word or phrase with the replacement text, leaves the rest of the message intact, and still sends it.
This tester and the word list are free to use. In your own app, TalkJS's forbidden word list is included on every plan, and every plan has a free development mode, so you can set it up and test it before you go live.