Getting Started

Discord Companion Bot on Windows

Published · Last updated

This guide sets up the Discord companion bot on a Windows machine using PowerShell: Windows Server 2016 or later, or Windows 10 or 11. The bot is what carries your Discord replies back to visitors. Visitor messages reach Discord without it.

It picks up after Steps 1 to 4 of the Discord Integration Setup Guide, so you have a Discord bot token, a channel ID, and the Discord tab saved in WordPress. Every command below goes in Windows PowerShell, which every Windows Server and Windows desktop includes.

What you need

  • Node.js 18 or later. Download the LTS Windows installer (.msi) from nodejs.org and install it with the default options. Open a new PowerShell window afterwards and check it with node --version.
  • Four values, all shown on the plugin’s Discord tab:
    • the Bot Token you pasted there,
    • the Channel ID,
    • the WordPress Endpoint URL and the Webhook Secret, both under Bot Connection Info.

Step 1: Copy the bot out of your WordPress folder

The bot ships inside the plugin at wp-content\plugins\super-speedy-chat\bot. Run it from its own folder outside your website, for two reasons: its .env file holds your bot token and webhook secret, which must never sit anywhere the web server can serve, and a plugin update replaces the whole plugin folder, which would delete your settings.

Change the first path to wherever your WordPress lives (for example C:\inetpub\wwwroot on IIS or C:\xampp\htdocs on XAMPP):

New-Item -ItemType Directory -Path C:\ssc-discord-bot
Copy-Item -Path "C:\inetpub\wwwroot\wp-content\plugins\super-speedy-chat\bot\*" -Destination C:\ssc-discord-bot
Set-Location C:\ssc-discord-bot
Get-ChildItem -Force

You should see discord-bot.js, package.json and env-example.

Step 2: Install the bot’s dependencies

npm.cmd install
Common mistake

Typing plain npm install on a default Windows setup fails with “npm.ps1 cannot be loaded because running scripts is disabled on this system”. That is PowerShell’s execution policy blocking npm’s PowerShell wrapper, not a problem with the bot. npm.cmd install runs the same npm without the wrapper and needs no policy change.

Step 3: Create your .env file

The bot reads its settings from a file called exactly .env in its folder. Rename the template:

Rename-Item env-example .env

If your bot folder has no env-example file, create .env by pasting this whole block into PowerShell in one go:

@"
# Discord Bot Token (from Discord Developer Portal > Bot > Token)
DISCORD_BOT_TOKEN=your_discord_bot_token_here

# Discord Channel ID (right-click channel > Copy Channel ID)
DISCORD_CHANNEL_ID=your_channel_id_here

# WordPress REST endpoint URL (from Super Speedy Chat > Discord > Bot Connection Info)
WP_ENDPOINT_URL=https://your-site.com/wp-json/ssc/v1/discord/incoming

# Webhook Secret (from Super Speedy Chat > Discord > Bot Connection Info)
WP_WEBHOOK_SECRET=your_webhook_secret_here
"@ | Set-Content .env

Then open it and replace the four placeholder values with yours:

notepad .env

Save and close Notepad. Each line is NAME=value with nothing else around the value: no quotes, no spaces.

Common mistake

Do not create or edit .env with echo ... > .env. In Windows PowerShell that writes the file as UTF-16, which the bot cannot read, and it then reports DISCORD_BOT_TOKEN is not configured in .env even though the token is there. Use Notepad or the Set-Content block above.

Step 4: Check the bot can reach WordPress

Before starting the bot, confirm this machine can reach your site and that the secret matches. This reads both values straight from your .env:

$cfg = Get-Content .env | Where-Object { $_ -match '^\s*[A-Z_]+\s*=' } | Out-String | ConvertFrom-StringData
curl.exe -s -X POST -H "Content-Type: application/json" -H "X-SSC-Secret: $($cfg.WP_WEBHOOK_SECRET)" -d '{}' $cfg.WP_ENDPOINT_URL
ReplyMeaning
{"code":"missing_params",...}Working. The bot can reach WordPress and the secret is right (the empty test message is rejected, as it should be).
{"code":"unauthorized",...}The secret in .env does not match Webhook Secret on the Discord tab.
{"code":"rest_no_route",...}The URL is wrong. Copy WordPress Endpoint URL from the Discord tab again.
An HTML page, or Could not resolve hostThe URL is wrong, or a firewall or security plugin is blocking the request.

Type curl.exe, not curl: in Windows PowerShell, curl is a different command with different options. curl.exe is part of Windows 10 (version 1803 or later), Windows 11 and Windows Server 2019 or later; on Windows Server 2016, skip this check and go straight to Step 5.

Step 5: Start the bot

node discord-bot.js

A working bot prints:

[SSC Bot] Logged in as YourBot#1234
[SSC Bot] Monitoring channel: 123456789012345678
[SSC Bot] Relaying to: https://your-site.com/wp-json/ssc/v1/discord/incoming

With the bot running, click Test Connection on the Discord tab in WordPress. Check 10, “Companion bot answers”, passes within a few seconds and the bot logs Answered a Test Connection from WordPress. For what every check means, see Testing the connection.

Reply in one of the chat threads in Discord and the bot logs Message relayed successfully, and the visitor sees your reply in the chat. Press Ctrl+C to stop the bot before the next step.

Step 6: Keep it running

The bot has to run all the time, restart itself if it ever stops, and start again when the server reboots. Two pieces do that.

A restart loop. This creates start-bot.cmd in the bot folder. It runs the bot, writes everything the bot prints to bot.log, and starts it again 10 seconds after it stops:

@"
@echo off
cd /d "%~dp0"
:loop
echo [%date% %time%] Starting bot>> bot.log
node discord-bot.js >> bot.log 2>&1
echo [%date% %time%] Bot stopped, restarting in 10 seconds>> bot.log
ping -n 11 127.0.0.1 > nul
goto loop
"@ | Set-Content C:\ssc-discord-bot\start-bot.cmd

A scheduled task that starts it at boot. Open PowerShell as Administrator (right-click PowerShell, Run as administrator) and run:

$action   = New-ScheduledTaskAction -Execute 'C:\ssc-discord-bot\start-bot.cmd' -WorkingDirectory 'C:\ssc-discord-bot'
$trigger  = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot' -Action $action -Trigger $trigger -Settings $settings -User 'SYSTEM' -RunLevel Highest
Start-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot'

The task runs in the background with no window, whether or not anyone is logged in. Check the bot started:

Get-Content C:\ssc-discord-bot\bot.log -Tail 20
Common mistake

Keep -ExecutionTimeLimit ([TimeSpan]::Zero). A scheduled task’s default time limit is 72 hours, after which Windows stops it, and Discord replies silently stop reaching visitors three days after every reboot.

Why this matters

Why a restart loop and not the task’s own “restart on failure” setting? That setting only covers a task that fails to start. When the bot starts and later exits, Task Scheduler treats the task as finished and leaves it stopped.

Lock down the .env file so only the bot (running as SYSTEM) and administrators can read your token. From the same Administrator PowerShell:

icacls C:\ssc-discord-bot\.env /inheritance:r /grant:r "SYSTEM:F" "Administrators:F"

Day-to-day commands

TaskCommand
Watch the log liveGet-Content C:\ssc-discord-bot\bot.log -Tail 20 -Wait
Stop the botStop-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot'
Start the botStart-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot'
Is it running?Get-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot' (State shows Running)

Updating the bot

When a plugin update changes the bot, stop it, copy the new files over (your .env, start-bot.cmd and bot.log are left alone), reinstall and start it again, from an Administrator PowerShell:

Stop-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot'
Copy-Item -Path "C:\inetpub\wwwroot\wp-content\plugins\super-speedy-chat\bot\discord-bot.js", "C:\inetpub\wwwroot\wp-content\plugins\super-speedy-chat\bot\package.json" -Destination C:\ssc-discord-bot
Set-Location C:\ssc-discord-bot
npm.cmd install
Start-ScheduledTask -TaskName 'Super Speedy Chat Discord Bot'

Then run Test Connection on the Discord tab: check 10 passing confirms the updated bot is running.

Troubleshooting

What you seeCause and fix
npm.ps1 cannot be loaded because running scripts is disabledUse npm.cmd install (Step 2).
ERROR: .env file not foundThe file is not named exactly .env. Run Get-ChildItem -Force in the bot folder: a name like .env.txt means Notepad or Explorer added an extension. Fix it with Rename-Item .env.txt .env.
ERROR: DISCORD_BOT_TOKEN is not configured in .envA value still has its your_... placeholder, or the file was written with > and is UTF-16. Recreate it with Step 3.
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING) straight after another errorNode crashing on its way out after the real error, which is the line above it. Fix that error. Copying in the discord-bot.js from the latest plugin version removes the crash itself.
Failed to login: An invalid token was providedThe token is wrong or was reset. Reset it in the Discord Developer Portal and paste the new one into both .env and the WordPress Discord tab.
Test Connection check 10: no answer from the companion botThe scheduled task is not running, DISCORD_CHANNEL_ID is a different channel, the bot cannot reach WP_ENDPOINT_URL (Step 4), or its discord-bot.js is older than 1.1.0. Follow Updating the bot.
WordPress returned 401 in the logWebhook secret mismatch. Recopy it from the Discord tab and restart the bot.
WordPress returned 404 in the logThe reply was in a thread the integration did not create. Reply inside the thread the chat opened.
'node' is not recognizedNode.js is not installed, or PowerShell was open before it was installed. Open a new PowerShell window.
Bot runs but replies do nothing, no log linesMessage Content Intent is off, or DISCORD_CHANNEL_ID is not the channel the threads are in.

Further reading

creating the Discord bot, inviting it and connecting WordPress
how the relay works, rotating the webhook secret, and running it on Linux
what the two-way bridge does day to day

Comments

▲
▼
1/1