Skip to content

Bans and Anti-Gaming

Two layers keep a queue fair: per-room anti-gaming rules that throttle join abuse, and a ban registry that keeps specific members out.

Rejoin cooldown

A cooldown stops leave-and-rejoin cycling for a better position. Set it at room creation (or later via update); 0 disables it:

snug waiting-room create -r launch-day -c 100 --anti-gaming-rejoin-cooldown 60

Verified: join, leave, then an immediate rejoin fails until the cooldown elapses:

{
  "status": 429,
  "msg": "Please wait 60 seconds before rejoining",
  "error": "RATE_LIMITED"
}

Join rate limit

Caps join attempts per member within a sliding window:

snug waiting-room create -r launch-day -c 100 \
  --anti-gaming-rate-limit-max 2 --anti-gaming-rate-limit-window 60

Verified: with a max of 2 per 60 seconds, the third join attempt inside the window fails with 429 RATE_LIMITED - Too many join attempts. Try again in 60 seconds. Both knobs take 0 to disable.

The service also watches request patterns - rapid join/leave cycling and suspiciously regular request timing - and can auto-ban members it flags; the thresholds are internal and not per-room configurable.

Rejecting with a ban

reject removes members from the queue; adding -b <seconds> also bans them from rejoining:

snug waiting-room reject -r launch-day -m user-3 -R "abuse" -b 3600

Verified: the rejected member's next join attempt fails with 403 FORBIDDEN - Banned until 2026-08-28T15:16:02+00:00.

The ban registry (admin)

Explicit bans are managed separately from rejection. All ban commands require a platform admin token, except member-bans, which a member may also call for themselves.

snug waiting-room ban -r launch-day -m user-4 -R "bot" -d 86400  # omit -d for permanent
snug waiting-room bans -r launch-day --include-expired
snug waiting-room ban-details -r launch-day -m user-4
snug waiting-room unban -r launch-day -m user-4
snug waiting-room member-bans -m user-4     # room IDs this member is banned from

bans lists a room's bans soonest expiry first, permanent bans last, and pages on the standard list contract (--limit, --cursor, --all).

An explicit ban records the full audit trail; captured live:

{
  "room_id": "launch-day",
  "member_id": "user-4",
  "reason": "bot",
  "banned_by": "docs-wave-admin",
  "banned_at": "2026-08-28T14:16:12.838659Z",
  "banned_until": "2026-08-28T16:16:12.838659Z"
}

Two verified gotchas:

  • A ban created via reject -b blocks joins and appears in the room's bans list (member ID and expiry only), but it has no registry record: ban-details on it comes back empty. Use ban when you need an auditable reason and actor.
  • Bans are per-room. member-bans aggregates the rooms a member is banned from; there is no global ban.

Expired bans stop blocking joins immediately and are swept from the registry in the background (hourly by default). The exact endpoints are in the Waiting Room API reference.