Documentation menu

Docs/Plugins/Censor

Censor

Filter invites, domains, words, tokens, zalgo, caps and mentions - with per-level and per-channel sub-configs and an anti-raid layer.

Censor watches every message (and some things that are not messages, like nicknames) and removes content that matches your rules. Violations can warn, and repeat violations can auto-mute.

plugins:
  censor:
    levels:
      0:                       # applies to regular members (level 0)
        filter_invites: true
        filter_zalgo: true
        blocked_words: [scamword]
      50:                      # applies to everyone up to level 50 (mods included)
        blocked_words: [superbadword]
    channels:
      665875009507426304:      # extra rules just for this channel
        filter_domains: true

Setup checklist

  1. Open Setup > Filters and add rules under level 0 for ordinary members. Do not put a normal member rule under level 50 unless moderators should be filtered too.
  2. Start with one literal test word in one private channel. Add that channel to an allowlist only after the enforcement test.
  3. Choose whether hits only delete, also warn, or escalate to a mute. A mute requires the infractions plugin, a working mute role, and role hierarchy.
  4. Subscribe a mod log channel to Censored message and any raid events you intend to use.
  5. Save and paste the exact message into the simulator with the test member's real level and channel.
  6. Post the same message as a regular test account. Confirm deletion, warning or mute, and the named config key in the log.
  7. Test one allowed near-match so the rule does not block more than intended.
  8. Add production lists and channels gradually. For image text, configure Image Scan OCR separately.

How rules are scoped

The top level holds two maps of sub-configs: levels and channels (extra rules per channel or category). A levels key is a ceiling: rules under it apply to members at or below that level. Rules under 0 apply only to regular members - trusted members, mods and admins are above them. To also filter staff, put the rules under a higher key like 50 or 100. Each sub-config carries the same filter set; the first matching rule wins.

The filters

  • Invites - filter_invites, with guild/vanity whitelists and blacklists (invites_guild_whitelist, invites_whitelist, invites_blacklist) and a per-channel exemption list.
  • Domains - filter_domains with domains_whitelist / domains_blacklist. Blocked domains match with or without https://, so a bare bad-site.com is caught too, subdomains included. The allow-list only judges real links (with a scheme), so ordinary text can never trip it. List entries are forgiving: paste a full link (https://bad-site.com/whatever) or just the domain - both mean the same thing, and a www. prefix is ignored.
  • Words and tokens - blocked_words (whole words) and blocked_tokens (substring matches - use these to catch n1tro-style respellings of a blocked word). Entries are matched literally, so $5 means a real dollar sign - you never need to escape anything, and a stray symbol can never break your filter. If you want actual regex matching, that lives in two places: a channel rule's text pattern (whitelist_text_regex, on the Channel Rules page - see the Utilities docs) and the AutoMod page's regex patterns, which Discord itself enforces.
  • Zalgo - filter_zalgo, plus block_zalgo_nicknames for names.
  • Caps - filter_all_caps. It only fires on repetition: a message counts when it carries at least all_caps_min_char_length capitals in a row, and the filter acts after all_caps_min_message_count such messages within all_caps_interval seconds. All three thresholds are editable right next to the toggle on the dashboard's Censor form.
  • Mentions / nicknames / hoisting - blocked_mentions (see below), blocked_nicknames, hoist_blacklist.
  • Message length - message_char_limit.

Blocked mentions

blocked_mentions protects specific people, roles, or channels from being pinged. Every entry needs a one-letter prefix saying what the id is - a bare id on its own matches nothing at all:

Prefix Blocks Example
u mentions of a user u80351110224678912
r mentions of a role r175028798551982080
c mentions of a channel c290923757399310346
plugins:
  censor:
    levels:
      0:
        blocked_mentions:
          - u80351110224678912     # the owner
          - r175028798551982080    # the admin role
        mention_channel_whitelist:
          - 290923757399310346     # staff channel, no filtering here

You can paste a mention straight from Discord (<@806…>, <@&175…>, <#290…>) and it is converted to the right prefixed form when the config is saved. What does not work is a plain id with no prefix, or the placeholder text uid / rid / cid - those never match anything, and the filter stays silent because there is nothing to match. If a blocked mention is not being caught, check the prefix first.

Ids are easiest to get with Developer Mode on in Discord (Settings, Advanced), then right-click a member, role, or channel and Copy ID.

What counts as a mention:

  • Typing the mention in a message.
  • Replying to someone with the @ left on. That pings them just like a written mention, so it is treated the same way. The log entry says (reply ping) so you can tell which form fired.
  • A reply with the ping switched off pings nobody, so it is left alone.

mention_channel_whitelist exempts channels where the filter should not run.

Most filters take a *_channel_whitelist to exempt specific channels. A whitelisted channel exempts its threads and forum posts too - the filters themselves also run inside threads, like everywhere else.

Escalation

  • warn_on_censor issues a warning infraction alongside the deletion.
  • mute_violations auto-mutes after mute_violations_count hits within mute_violations_interval seconds, for mute_violations_duration seconds. All three numbers are editable next to the "Mute repeat offenders" toggle on the dashboard's Censor form.

Anti-raid

The antiraid block goes inside a level, next to that level's filters (plugins.censor.levels.0.antiraid), not at the top of the censor block.

It watches join velocity: count joins within interval seconds starts a lockdown for lockdown_duration seconds. While it is active, every new join receives raid_action - a quarantine role (raidrole), a kick, a ban, or a tempban for raid_action_duration - and notifyrole gets pinged. That ping goes to the first mod log channel subscribed to the Raid detected event, so give one of your log channels that event or the ping has nowhere to go.

The optional shield block pauses server invites and/or member DMs at the Discord level (pause_invites, pause_dms) for the lockdown window, so the influx stops at the source.

You can also drive the lockdown by hand:

  • !raid status (or bare !raid) - is a lockdown active, and for how much longer.
  • !raid on [duration] - start (or extend) the lockdown manually, for example ahead of a raid you can see forming. New joins receive the configured raid_action exactly as if the detector had tripped, and the shield goes up if configured. Duration defaults to lockdown_duration.
  • !raid off - lift the lockdown early and return quarantined members to normal (strips raidrole).

Manual enables and lifts write their own mod log entries naming the moderator, alongside the automatic raid detection events.

Testing your rules

Setup → Filters includes a message simulator: paste a message, pick the channel and the member's level, and it shows exactly which censor rule (if any) would catch it - the same first-hit-wins order the bot uses. Every hit names the exact config key that fired (for example plugins.censor.levels.50.blocked_words), so you can jump straight to that line in your config to change or whitelist it.

Commands

Arguments in {curly braces} are required. Arguments in [square brackets] are optional.

Command What it does
/antiraid [action] Inspect, manually enable, or lift the anti-raid lockdown: status / on [duration] / off.

Image-based scams are the Image Scan plugin's job; when its OCR layer is on, text found inside images is run through these same censor lists.

Troubleshooting

  • The simulator catches a message but live Discord does not: confirm the live member level, channel scope, bot Manage Messages permission, and that the plugin block saved.
  • A blocked word catches too little: blocked_words uses whole words; use blocked_tokens for substring variants.
  • A domain entry behaves oddly: paste the domain or full URL. The loader normalizes schemes and www..
  • A reply ping slips through: user entries need the u prefix and the reply must have its ping left on.
  • Mute escalation records a hit but cannot mute: configure the infractions mute role below the bot and check Manage Roles.
  • Raid alerts do not ping: notifyrole uses the first mod log channel subscribed to Raid detected, so that subscription must exist.