Docs · Running your bot

A web server in your bot: webhooks and dashboards

All docs

Most bots only connect out to Discord and never need this. If yours has to receive something (a vote webhook from a bot list, a GitHub webhook, a small status page), your server already has a public port for it.

Your address and port

Open Network in the panel. The address and port there are reachable from the internet. Your program gets the port as the SERVER_PORT environment variable, so it never needs typing into your code.

Listen on it

Listen on 0.0.0.0 (every interface) and SERVER_PORT. Not the address shown on the Network page: inside the server that address does not exist, and binding to it fails.

# Python, aiohttp, next to a discord.py bot
import os
from aiohttp import web

async def vote(request):
    data = await request.json()
    print("vote from", data.get("user"))
    return web.Response(text="ok")

async def start_web():
    app = web.Application()
    app.router.add_post("/vote", vote)
    runner = web.AppRunner(app)
    await runner.setup()
    await web.TCPSite(runner, "0.0.0.0", int(os.environ["SERVER_PORT"])).start()

# call `await start_web()` from your bot's setup_hook
// JavaScript, Node's own http module, next to a discord.js bot
const http = require("node:http");

http.createServer((req, res) => {
  if (req.method === "POST" && req.url === "/vote") {
    let body = "";
    req.on("data", (chunk) => (body += chunk));
    req.on("end", () => { console.log("vote:", body); res.end("ok"); });
  } else {
    res.statusCode = 404;
    res.end();
  }
}).listen(Number(process.env.SERVER_PORT), "0.0.0.0");

Run the web server in the same process as the bot, as above. A second program in the same server needs your start script to launch both.

Then give the other service the address: http://, the address and port from the Network page, and your path, for example http://203.0.113.10:25570/vote.

What you do not get

  • HTTPS. The port speaks whatever your program speaks, which is plain HTTP in the examples above. Most bot list webhooks accept an http:// URL. Services that insist on HTTPS need a tunnel: a Cloudflare Tunnel run from inside your bot (cloudflared connects out, so nothing else is needed) gives you an HTTPS address on a domain you own.
  • A domain name. The address is an IP and a port. Pointing your own domain at it works for HTTP, as long as the port is part of the URL.
  • Ports 80 and 443. You get the one port on the Network page.

Check the sender

Anyone who finds the address can send requests to it. Bot lists and GitHub let you set a secret that is sent with each webhook: check it before trusting what arrived, and reply 401 when it does not match.

Something here wrong or out of date? Tell us and it gets fixed.