JoinGG

Handling Toxic Players Without Killing Your Community

Word filters fail within a day, and the hardest call is a regular everyone likes. How graduated mutes, honest reports and firm calls keep a server civil.

SweetMask · 8 min read

Someone said something ugly on your server on Friday night. By Sunday you had five messages about it, only one of them from a player who was actually in the round, and two of your regulars had stopped speaking to each other. You spent the weekend reading logs instead of playing. The first thing you reached for was a word filter, and a word filter would not have caught it, because nothing that was said appears on any list.

That is the ordinary shape of moderation on a community server, and it is why most moderation advice is useless. The advice assumes the hard part is detecting bad words. The hard part is deciding what a specific person deserves, in front of an audience who will read your decision as a statement about what kind of place this is.

Here is the order to get things right in, roughly by how much each one actually changes the temperature of your server.

1. A blanket word filter is the least useful thing you will build

It fails in three ways at once.

It catches the wrong people. Substring matching is why the Scunthorpe problem is named after a town: any filter that blocks a string inside a larger word will flag place names, surnames and ordinary vocabulary. A player writing assassin, analysis or the name of a British town gets their message eaten, decides your chat is broken, and stops typing. That is a real cost paid by people doing nothing wrong.

It gets routed around in an evening. The standard evasions take no skill: leetspeak substitutions, a zero-width space (U+200B) dropped into the middle of a word, a Cyrillic а (U+0430) standing in for a Latin a, or single spaces between letters. Worse, the filter tells the determined player exactly where the line sits. They probe it, find the variant that passes, and now they can say the thing with the added pleasure of having beaten you.

It punishes the wrong register. Get wrecked, you absolute muppet between two people who have played together for two years is, to a regular expression, identical to the same sentence typed at somebody on their first join. A filter cannot see the relationship, so it lands on the harmless case and misses the one that actually drove a new player away.

Filters are genuinely good at a narrow set of things: link and invite spam, adverts for a rival server, and the small handful of slurs that have no innocent substring. Keep that list short and specific, and expect it to do nothing else.

2. Normalise the text, then stop expanding the list

If you keep a filter, do the one thing that raises the cost of evasion meaningfully: clean the text before you match it. Strip zero-width and other non-printing characters, apply Unicode NFKC normalisation to fold fullwidth and compatibility forms back to plain letters, and then map lookalikes through the Unicode confusables table from UTS #39, so a Cyrillic а stops counting as a different character from a Latin one. NFKC on its own will not do that last step, which is exactly why homemade filters keep losing to a single swapped letter.

Then stop. Every entry you add past the obvious ones buys you one more evasion variant and one more false positive, and the ratio only gets worse.

Run any new rule in alert-only mode first. Discord's AutoMod supports exactly this: a keyword or spam rule can alert a moderator channel rather than blocking the message. Leave a new rule in that state for a fortnight and read what it actually caught before you let it act. The wider changes Discord has made to community servers have pushed a lot of owners into copying somebody else's AutoMod config wholesale, which is how you end up blocking your own regulars for reasons nobody can explain.

3. Graduated response is the mechanism, and the ladder has to be visible

The ladder is warn, short mute, long mute, kick, ban. Nothing clever. What makes it work is that every rung is reversible except the last one, so you can be wrong cheaply.

The tooling exists in every ecosystem, and it is worth knowing which one you are in. On Source-engine servers such as Team Fortress 2 and Garry's Mod, SourceMod's basecomm gives you sm_gag for text, sm_mute for voice and sm_silence for both, gated behind the ADMFLAG_CHAT flag, with sm_ungag and friends to reverse them; SourceComms layers timed punishments and a shared database on top. Counter-Strike 2 is not a SourceMod platform — the stack there is Metamod:Source plus CounterStrikeSharp, with an admin plugin such as CS2Fixes supplying kick, ban, mute and gag. On Minecraft, LiteBans templates escalate automatically: a warning category can be configured so that the third warning fires the next punishment without a human deciding again. If you are choosing a framework, the comparison of SourceMod, AMX Mod X and Oxide covers what each one can and cannot express.

The part almost everyone skips is publishing the ladder. Write the rungs and the durations into your rules, and write down what resets them — warnings expiring after ninety days, say. A player who gets a thirty-minute mute and can see that thirty minutes is step two of five behaves entirely differently from a player who believes staff mute people according to mood. Ladders only deter when they are legible, which is the same reason rules people actually read outperform a wall of text nobody opens.

4. A toxic player and a bad night look identical in the moment

The incident tells you nothing on its own. The history tells you everything.

Two things to check before you decide. First, what proportion of this person's record is this one event? Three hundred hours on the server and a single blow-up in a losing round is a bad night. Four hours spread over two weeks with three incidents in them is a pattern. Second, who was it aimed at? Abuse that lands on whoever is bottom of the scoreboard, every time, is not temper — it is a hobby.

Then ask them. A short private message saying that was out of order and what was going on separates the two groups almost perfectly. The person having a bad night apologises before you tell them to. The person for whom this is the point argues about whether the rule is fair.

Bad night: short mute and a note on their record. Pattern: skip a rung and say why.

5. Make reporting cost the reporter something

A one-click report button becomes a weapon within a month. It gets used to remove a good player from a lobby, to settle an argument from three weeks ago, and to farm attention. The fix is not to make reporting hostile — it is to require enough work that a false report is not free.

Ask for a locator and the exact words: the map or round, the approximate time, and the line pasted verbatim. On Source engine you can ask for the demo and a tick number. On Minecraft you can hand them a timestamp format and grep your chat log. This is not friction for its own sake. It filters for reports where something actually happened, and it gives you the one thing you need to be fair — the ability to check rather than to arbitrate between two accounts.

There is a Minecraft wrinkle worth deciding deliberately. Since 1.19.1, chat messages are cryptographically signed and clients can report them straight to Mojang, whose action lands on the account across every server rather than only yours. enforce-secure-profile in server.properties controls whether your server requires signed profiles. Turning it off is a defensible privacy choice, but understand what you are switching off: the channel that removes a genuinely dangerous person from the platform, not just from your box.

6. The loudest complainer is usually not the person who was hurt

The player who was actually targeted very often says nothing. They finish the round, close the game and never come back, which is the same failure mode behind most of the reasons nobody joins your server — the people you lose do not file a report explaining why.

Meanwhile the five messages in your inbox are frequently from third parties: someone with a prior grievance, someone who enjoys the process, someone relaying a version of events they got secondhand. So before acting, find the person named as the target and ask them directly. A fair share of the time they will tell you it was fine and they had already forgotten it.

You are not moderating messages. You are moderating whether the eleventh person who joined tonight comes back on Thursday, and almost all of them decide that silently.

Here is the call that actually keeps moderators awake. You have a regular who plays four nights a week, who is funny, who fills the server on a dead Tuesday, and who is the reason three new players left within twenty minutes over the last fortnight. Nobody has reported him. You know anyway, because you were there.

The arguments for keeping him are not stupid. He does bring people. Your staff like him. Removing him costs you a visible chunk of your weeknight population, immediately, and some goodwill from people who will think you overreacted.

Remove him anyway.

Do it in this order. One private conversation, with the three specific incidents named and no negotiation about whether they happened — you are not gathering evidence, you are telling him. State the condition and the consequence in the same breath. If it recurs, apply the ladder exactly as published, at the rung anyone else would get, without a discount for tenure. Then say plainly, once, in your Discord, that a player was actioned for how they treat new joiners, without a list of grievances and without naming a victim.

The reason to commit to this is arithmetical rather than moral. You can count the regulars you lose, because they announce it. You cannot count the players who joined, listened for ten minutes and closed the game, and there are more of them. Your position in the browser and your standing on a server directory are built by people who stayed, so the leak never appears in a number you can look at. Every night you keep him, you pay that bill with strangers' patience.

Expect him back on an alt account inside a day, sometimes inside an hour, which is a separate problem with its own tooling — see detecting ban evasion and alt accounts, and be clear-eyed about the fact that IP-level countermeasures come with their own casualties, which is the whole argument in should you block VPN players.

The ladder does the work. Your job is to keep it short, publish it, and apply it unchanged to the person you like.

Common questions

How can you tell if an AutoMod filter rule is producing false positives?
Run the new rule in alert-only mode first. In Discord's AutoMod, keywords can alert a moderator channel instead of blocking messages. Leaving a rule in this alert-only state for a fortnight lets you review what it actually catches before letting it act.
What happens when enforce-secure-profile is disabled on a Minecraft server?
Disabling enforce-secure-profile in server.properties turns off the requirement for cryptographically signed chat messages. This switches off the reporting channel that allows Mojang to action a dangerous player's account across every server rather than just your own.
What details should you require from players when they submit a report?
Require a locator and the verbatim text of the incident. Depending on your game ecosystem, ask for the map or round, approximate time, a pasted quote, a demo with a tick number on Source engine, or a specific timestamp format to search Minecraft logs.
Tags
moderationcommunity managementserver administrationchat filtersbans
Share

SweetMask

Published · 8 min read

All articles

Keep reading