Skip to content

PingusWasHere/RobloxBanSystemBot

Repository files navigation

Roblox Discord Admin

A production-oriented Discord bot and Roblox server bridge for remotely moderating a Roblox experience.

The project uses Discord slash commands, Discord Components V2, Roblox Open Cloud User Restrictions, Open Cloud Messaging Service, local JSON or PostgreSQL storage, signed server messages, role-based permissions, audit logs, and persistent temporary-ban reconciliation.

Official Discord and Roblox documentation was reviewed on June 15, 2026.

Overview

Capability Description
Permanent bans Block a Roblox user from the entire experience
Temporary bans Apply a restriction with a controlled expiration
Unbans Remove an active Roblox restriction and update the local case
Live kicks Send a best-effort kick request to active Roblox servers
Case management Inspect, edit, cancel, filter, and paginate moderation cases
Player history Review every locally recorded action for a Roblox user
Roblox profiles Display public account information, avatar, and local ban status
System health Inspect Discord latency, database health, Roblox activity, and request status
Audit logging Send moderation actions and technical errors to separate Discord channels

The system works even when the target player is offline. Persistent access control is handled by Roblox User Restrictions, while Messaging Service handles best-effort real-time notifications to active game servers.

Key Features

Area Included
Runtime Modern JavaScript ES modules, Node.js, no TypeScript
Discord Slash commands, Components V2, ephemeral confirmations
Roblox Open Cloud User Restrictions and Messaging Service
Database Local JSON by default or PostgreSQL for shared deployments
Cases Sequential case numbers such as RBX-000001
Reliability Mutation verification, idempotency keys, retries, and timeouts
Security HMAC-SHA256, expiration checks, nonces, and replay protection
Permissions Guild, role, administrator, and protected-user checks
Rate control Per-user and global sensitive-action cooldowns
Logging Separate moderation audit and technical error channels
Scheduling Persistent temporary-ban reconciliation after restarts
Quality Automated tests, ESLint, Prettier, and GitHub Actions CI
Deployment Windows, Linux, and VPS compatible

Roblox User Restrictions is the source of truth for whether a user may join. The configured database is the bot's operational record and audit history. Messaging Service is not treated as proof that a server received or executed a message.

Requirements

Requirement Recommendation
Node.js Node.js 24 LTS
npm Version 10 or newer
Discord Application, bot, guild, and moderation channels
Roblox Published experience with Studio publishing access
Open Cloud API key with the required experience permissions
Storage Writable disk for JSON, or access to PostgreSQL

Quick Start

1. Install dependencies

PowerShell:

Copy-Item .env.example .env
npm install

Linux or macOS:

cp .env.example .env
npm install

2. Configure Discord and Roblox

Open .env and fill every required value. Never commit this file.

3. Validate the project

npm run validate-startup
npm test
npm run lint
npm run format:check

4. Deploy slash commands

npm run deploy-commands

Commands are deployed to DISCORD_GUILD_ID, which makes development updates appear quickly in the configured guild.

5. Start the bot

npm start

Development mode with automatic restarts:

npm run dev

Discord Setup

Create the application

  1. Open the Discord Developer Portal.
  2. Select New Application.
  3. Enter a name and create the application.
  4. Open General Information and copy the Application ID.
  5. Set DISCORD_CLIENT_ID to that value.

Create the bot

  1. Open the Bot page.
  2. Create the bot if Discord has not created one automatically.
  3. Reset and copy the bot token.
  4. Set DISCORD_TOKEN in .env.
  5. Do not enable privileged intents. This project only requests the Guilds intent.

Invite the bot

  1. Open OAuth2 > URL Generator.
  2. Select the bot scope.
  3. Select the applications.commands scope.
  4. Grant:
    • View Channels;
    • Send Messages;
    • Read Message History.
  5. Open the generated URL and invite the bot.

Collect IDs

Enable Discord Developer Mode under User Settings > Advanced.

Copy:

  • the guild ID into DISCORD_GUILD_ID;
  • the moderation log channel ID into DISCORD_LOG_CHANNEL_ID;
  • the technical error channel ID into DISCORD_ERROR_CHANNEL_ID;
  • every moderation role ID into the appropriate role list.

Role lists accept comma-separated values:

DISCORD_BAN_ROLE_IDS=111111111111111111,222222222222222222

Permission model

Role group Allowed actions
Admin roles Every command
Discord administrators Every command when ALLOW_DISCORD_ADMINISTRATORS=true
Moderator roles Kick and read-only commands
Ban roles Ban and edit active bans
Kick roles Kick
Unban roles Unban and cancel active bans
View-case roles Case, history, sanctions, profile, status, and ping

Permissions are enforced in application code. Hiding a command in Discord is not considered a security boundary.

Roblox Open Cloud Setup

Create the API key

  1. Open Creator Dashboard > Credentials.
  2. Create an API key.
  3. Restrict it to the target experience.
  4. Restrict source IP addresses to your VPS when possible.
  5. Add only the permissions required by this project.

Required permissions:

Product or scope Permission
User Restrictions universe.user-restriction:read
User Restrictions universe.user-restriction:write
Messaging product messaging-service
Messaging operation universe-messaging-service:publish

Set the key as ROBLOX_OPEN_CLOUD_API_KEY.

Find the Universe ID

In Creator Dashboard:

  1. Open Creations.
  2. Find the experience.
  3. Open its menu.
  4. Select Copy Universe ID.
  5. Set ROBLOX_UNIVERSE_ID.

Find the Place ID

Open the place page or Studio configuration and copy the numeric place ID. Set ROBLOX_PLACE_ID.

The current implementation applies universe-level restrictions. The Place ID is retained for diagnostics and future place-scoped support.

Install the server bridge

Follow roblox/INSTALLATION.md.

The API key must never be placed in Roblox Studio. Only the HMAC command secret is shared with the server bridge.

Environment Reference

Core

Variable Required Purpose
NODE_ENV Yes development, test, or production
LOG_LEVEL Yes Structured log level

Database

Variable Default Purpose
DATABASE_PROVIDER json Select json or postgres
DATABASE_PATH ./data/database.json Local JSON file path
DATABASE_URL Empty PostgreSQL connection URL
DATABASE_SCHEMA roblox_discord_admin PostgreSQL schema used by this installation
DATABASE_SSL_MODE require PostgreSQL TLS mode: require or disable
DATABASE_POOL_MAX 10 Maximum PostgreSQL connection pool size

Database Modes

Mode Best for Shared between machines Extra service
JSON One bot process on one machine No No
PostgreSQL Hosted or multi-instance systems Yes Yes

Local JSON

JSON is the default. The bot creates data/database.json automatically on first startup.

DATABASE_PROVIDER=json
DATABASE_PATH=./data/database.json

Only one running bot process should write to a JSON database file. The in-process write queue prevents concurrent command writes from corrupting the file, but JSON is not a network database and must not be shared through a synchronized folder.

PostgreSQL

Use PostgreSQL when several bot instances need the same data, when the filesystem is temporary, or when the database is hosted separately.

DATABASE_PROVIDER=postgres
DATABASE_URL=postgresql://user:password@host:5432/database
DATABASE_SCHEMA=roblox_discord_admin
DATABASE_SSL_MODE=require
DATABASE_POOL_MAX=10

The bot creates its schema, tables, indexes, and migrations automatically. Hosted providers such as Neon, Supabase, Railway, or any compatible PostgreSQL server can be used.

Deployment goal Schema configuration
Multiple instances sharing the same data Use the same DATABASE_URL and DATABASE_SCHEMA
Separate bots on one PostgreSQL database Give each installation a unique DATABASE_SCHEMA
Local PostgreSQL without TLS Set DATABASE_SSL_MODE=disable only on a trusted network

The project does not automatically import old SQLite data. Back up and migrate legacy data before replacing an existing installation.

Discord

Variable Required Purpose
DISCORD_TOKEN Yes Bot token
DISCORD_CLIENT_ID Yes Discord application ID
DISCORD_GUILD_ID Yes Guild used for command deployment
DISCORD_LOG_CHANNEL_ID Yes Moderation audit channel
DISCORD_ERROR_CHANNEL_ID Yes Technical error channel
ALLOW_DISCORD_ADMINISTRATORS Yes Automatically trust Discord administrators
DISCORD_ADMIN_ROLE_IDS No Full-access roles
DISCORD_MODERATOR_ROLE_IDS No General moderator roles
DISCORD_BAN_ROLE_IDS No Ban roles
DISCORD_KICK_ROLE_IDS No Kick roles
DISCORD_UNBAN_ROLE_IDS No Unban roles
DISCORD_VIEW_CASES_ROLE_IDS No Read-only moderation roles

Roblox

Variable Required Purpose
ROBLOX_OPEN_CLOUD_API_KEY Yes Open Cloud authentication
ROBLOX_UNIVERSE_ID Yes Target experience universe
ROBLOX_PLACE_ID Yes Target place metadata
ROBLOX_MESSAGING_TOPIC Yes Cross-server topic
ROBLOX_COMMAND_SECRET Yes HMAC secret, minimum 32 characters

Moderation

Variable Default Purpose
DEFAULT_BAN_REASON No reason provided Fallback visible ban reason
DEFAULT_KICK_REASON No reason provided Fallback kick reason
MAX_TEMP_BAN_DURATION 365d Maximum temporary ban
COMMAND_COOLDOWN_SECONDS 3 Per-user command cooldown
GLOBAL_SENSITIVE_COOLDOWN_MS 750 Global sensitive-action cooldown
CONFIRM_DANGEROUS_ACTIONS true Dangerous action confirmation setting
CONFIRMATION_TIMEOUT_SECONDS 60 Confirmation lifetime
SCHEDULER_INTERVAL_SECONDS 60 Expiration reconciliation interval
ROBLOX_HTTP_TIMEOUT_MS 10000 Roblox HTTP timeout
ROBLOX_HTTP_MAX_RETRIES 3 Maximum safe retries
PROTECTED_ROBLOX_USER_IDS Empty User IDs blocked from destructive actions

Generate a Command Secret

PowerShell:

[Convert]::ToHexString(
  [Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
).ToLower()

Linux or macOS:

openssl rand -hex 32

Use the exact same value for:

  • ROBLOX_COMMAND_SECRET in .env;
  • CommandSecret in roblox/AdminConfig.lua.

Slash Commands

Command Purpose
/ban user duration reason internal-note alt-detection private Create a temporary or permanent ban
/unban user reason case Remove an active restriction
/kick user reason private Publish a best-effort live kick
/case number Display a moderation case
/history user Display a player's case history
/sanctions status type moderator player Filter and paginate cases
/roblox-user user Display a Roblox public profile and local status
/sanction-edit case duration reason internal-note alt-detection Edit an active ban
/sanction-cancel case reason Cancel an active ban
/status request-id Display system or request health
/ping Display Discord latency

Accepted durations

Input Meaning
30s 30 seconds
10m 10 minutes
2h 2 hours
7d 7 days
2w 2 weeks
1mo 30 days
1y 365 days
permanent Permanent ban
perm Permanent ban

After changing command names, descriptions, or options, run:

npm run deploy-commands

Moderation Workflows

Ban

  1. Resolve the input to a Roblox user ID.
  2. Create a pending database case.
  3. Apply the Roblox User Restriction with an idempotency key.
  4. Read the restriction back from Roblox.
  5. Mark the case active only after verification.
  6. Publish a signed ban-notification message.
  7. Active servers kick the player if present.
  8. Send a Discord audit record.

If Messaging Service fails after Roblox accepts the restriction, the ban remains active and the case records a warning.

Unban

  1. Resolve the target account and active local case.
  2. Read the current Roblox restriction.
  3. Send active=false with an idempotency key.
  4. Read the restriction again.
  5. Revoke the local case only after Roblox confirms it is inactive.
  6. Publish an unban-notification.

An already inactive restriction is handled idempotently and still receives an auditable unban case.

Kick

A kick publishes a signed message to active game servers. Each server checks whether it owns the target player before calling Player:Kick().

Messaging Service delivery is best effort. A successful HTTP response confirms publication, not that a server received the message or kicked the player.

Temporary ban expiration

Roblox enforces the configured restriction duration. The scheduler also scans expired active cases after startup and on a fixed interval. If Roblox still reports the restriction as active, the bot explicitly removes it before marking the local case expired.

Security Model

  • Secrets are loaded from .env.
  • .env, local JSON database files, backups, and logs are ignored by Git.
  • Configuration is validated before startup.
  • Roblox requests have timeouts and bounded retries.
  • 429 responses honor Retry-After.
  • Mutations use idempotency keys.
  • User IDs are the primary identity, never display names.
  • PostgreSQL uses parameterized queries.
  • Confirmations use opaque, expiring, single-use tokens.
  • Button ownership is verified.
  • Guild and role permissions are enforced server-side.
  • Technical errors do not expose secrets publicly.
  • Logs redact token, key, secret, authorization, and cookie fields.
  • The Roblox bridge exposes no client moderation RemoteEvent.
  • Game messages use HMAC-SHA256, expiration, nonces, and replay tracking.

The HMAC secret is present in published server code. It is not replicated to ordinary clients, but it is less protected than a secret stored only on your external server. Rotate it after team changes or suspected source access.

Official API Endpoints

Service Method Endpoint
User Restrictions GET https://apis.roblox.com/cloud/v2/universes/{universe_id}/user-restrictions/{user_id}
User Restrictions PATCH https://apis.roblox.com/cloud/v2/universes/{universe_id}/user-restrictions/{user_id}
Messaging Service POST https://apis.roblox.com/cloud/v2/universes/{universe}:publishMessage
Username resolution POST https://users.roblox.com/v1/usernames/users
User search GET https://users.roblox.com/v1/users/search
User profile GET https://users.roblox.com/v1/users/{userId}
Avatar thumbnail GET https://thumbnails.roblox.com/v1/users/avatar-headshot

User Restrictions is currently documented as Beta. Temporary restriction durations use protobuf duration strings such as 604800s. Permanent restrictions omit the duration field.

Important Limits

User Restrictions

Operation Documented limit
Get restriction 50 requests/second per universe
List restrictions 50 requests/second
Update restrictions 10 requests/second
Update the same user 2 requests/minute
General API key owner 150 requests/second

Messaging Service

Resource Documented limit
Topic length 80 characters
Message size 1,024 characters
Messages sent per game server 600 + 240 * player count per minute
Messages received per topic 40 + 80 * server count per minute
Messages received by the experience 400 + 200 * server count per minute
Subscriptions per server 20 + 8 * player count
Subscription requests 240 per minute per server

Limits may change. Recheck official documentation before high-volume deployment.

Development Commands

Command Purpose
npm start Start the production bot
npm run dev Start with automatic restarts
npm run deploy-commands Deploy guild slash commands
npm test Run the automated test suite
npm run lint Run ESLint
npm run format Format supported files
npm run format:check Verify formatting without changing files
npm run validate-startup Load configuration, database, services, and commands offline

Testing Before Production

  1. Run every local validation command.
  2. Deploy commands to a test Discord guild.
  3. Use a private published Roblox experience.
  4. Test a kick on an online test account.
  5. Test a 2-minute temporary ban.
  6. Confirm the test account cannot rejoin.
  7. Confirm the account is allowed back after expiration.
  8. Test a permanent ban and unban.
  9. Test permission denial with a non-moderator Discord account.
  10. Verify internal notes do not appear to read-only roles.
  11. Verify audit logs and technical error logs use separate channels.
  12. Restart the bot during a temporary ban and verify reconciliation.

Never test destructive actions on production staff or owner accounts. Add protected Roblox IDs to PROTECTED_ROBLOX_USER_IDS.

Production Deployment

Windows

Run the bot through a service manager or a dedicated process supervisor. At minimum:

npm ci --omit=dev
npm run deploy-commands
npm start

Store .env outside any public web directory and restrict filesystem access to the service account.

Linux with systemd

Install production dependencies:

npm ci --omit=dev

Example service:

[Unit]
Description=Roblox Discord Admin
After=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/roblox-discord-admin
ExecStart=/usr/bin/node src/index.js
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
User=roblox-admin
Group=roblox-admin

[Install]
WantedBy=multi-user.target

Then:

sudo systemctl daemon-reload
sudo systemctl enable --now roblox-discord-admin
sudo systemctl status roblox-discord-admin

The service account must be able to write to data/ and logs/.

Database Backup

Provider Recommended backup method
JSON Stop the bot, copy data/database.json, then restart the bot
PostgreSQL Use the hosting provider's backups or pg_dump with the configured database URL

Example JSON backup:

Copy-Item data/database.json data/database.json.backup

Test restoration regularly. A backup that has never been restored is not a verified backup.

Key Rotation

Roblox Open Cloud API key

  1. Create a replacement key with the same minimal permissions.
  2. Update .env.
  3. Restart the bot.
  4. Test /status and one safe request.
  5. Revoke the old key.

HMAC command secret

  1. Generate a new secret.
  2. Update .env.
  3. Update AdminConfig.lua.
  4. Publish the Roblox experience.
  5. Restart the bot.
  6. Restart private test servers and test a kick.

HMAC rotation is not atomic across already-running Roblox servers. Plan it during a quiet maintenance window.

Troubleshooting

Problem Resolution
Roblox returns 401 Verify ROBLOX_OPEN_CLOUD_API_KEY; the key is missing or invalid
Roblox returns 403 Recheck the experience, source IP restrictions, and required permissions
Roblox returns 404 Verify the Universe ID, user ID, resource scope, and API key access
Roblox returns 429 Wait for Retry-After; the bot retries only bounded, safe operations
Commands do not appear Run npm run deploy-commands and verify the client ID, guild ID, and applications.commands scope
Discord logs are missing Verify both channel IDs and the View Channels, Send Messages, and Read Message History permissions
Kick publishes but the player stays online Check whether the player is online, the topic matches, the bridge subscribed, and Messaging Service limits were not reached
Bans behave differently in Studio Publish the experience and test in a private production server

Contributing

Read CONTRIBUTING.md before opening a pull request.

Security issues should follow SECURITY.md, not a public issue.

License

Released under the MIT License.

Official Documentation


Created and maintained by Pingus.

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors