Using DOM manipulation in Discord bot throws document undefined error

I’m working on a Discord bot using JavaScript and ran into a problem. I found some browser code online for a number guessing game and tried to adapt it for my bot.

if (message.content === "!NumberGame"){
    let secretNum = Math.floor(Math.random() * 50) + 1;
    const playerGuesses = document.querySelector('.player-guesses');
    const gameResult = document.querySelector('.game-result');
    const hintText = document.querySelector('.hint-text');
    const submitBtn = document.querySelector('.submit-btn');
    const inputBox = document.querySelector('.input-box');
    let attemptCount = 1;
    let restartBtn;
}

When I run this code I get an error saying “ReferenceError: document is not defined”. The error happens when my bot tries to execute the querySelector lines. I understand this is browser code but I’m not sure how to make it work in a Discord bot environment. How can I fix this issue and make a simple guessing game work in my Discord bot without using DOM elements?

The document object doesn’t exist in Node.js - that’s browser-only stuff, and Discord bots run on Node.js. Hit this same wall when I was porting web games to my first bot.

You’ll need to completely rethink the approach. Instead of DOM elements showing game state, everything has to go through Discord messages. Store your secret number and attempt count as variables - tie them to the user ID or channel. When someone guesses, compare their message to your stored number and fire back with message.channel.send().

I’d also add a timeout since people bail on games halfway through. Same logic, just swap HTML manipulation for text responses.

The Problem: Your Flask app and Discord bot are failing to run concurrently on Heroku because you’re attempting to manage them within a single dyno using a combination of threading and asyncio. This approach creates race conditions during startup, leading to one service preventing the other from initializing correctly. Heroku’s dynos expect a single process; your multi-threaded approach violates this expectation.

:thinking: Understanding the “Why” (The Root Cause):

Heroku’s web dynos are designed to handle single-threaded applications. When you deploy your application, the Heroku router attempts to establish a connection to your web server (Flask) on the port specified by the PORT environment variable. However, because your runner.py uses threading to start both the Flask app and Discord bot, and the bot’s asyncio event loop runs forever, it blocks the main thread. This prevents the Flask server from properly binding to the port before the dyno’s 60-second timeout expires, resulting in failure. While this approach might function locally, the dynamics of Heroku’s process management make it unsuitable.

:gear: Step-by-Step Guide:

Step 1: Separate Your Services into Different Dynos. The most reliable solution is to run your Flask app and Discord bot on separate Heroku dynos. This eliminates the threading conflicts and aligns with Heroku’s architecture.

Step 2: Update Your Procfile. Modify your Procfile to define separate processes for your web server and worker (Discord bot):

web: gunicorn server:web_app
worker: python runner.py

Step 3: Modify server.py to Use the PORT Environment Variable. Ensure your Flask app uses the port provided by Heroku’s PORT environment variable:

import threading
import os
from flask import Flask

web_app = Flask(__name__)

@web_app.route('/')
def home():
    return 'Server is running'

def start_web_server():
    port = int(os.environ.get('PORT', 5000)) # Use Heroku's PORT or default to 5000
    web_app.run(host='0.0.0.0', port=port)

def launch_async():
    web_thread = threading.Thread(target=start_web_server)
    web_thread.daemon = True
    web_thread.start()

Step 4: Deploy and Scale Dynos. Deploy your updated application to Heroku. Then, scale your worker dyno to at least one instance using heroku ps:scale worker=1. This will ensure your Discord bot runs continuously.

:mag: Common Pitfalls & What to Check Next:

  • Dyno Startup Timeouts: Heroku dynos have a limited startup time. If your Discord bot takes too long to initialize, it might still cause issues. Optimize your bot’s startup process for faster initialization.
  • Resource Limits: Monitor your dyno usage. If your application consumes too many resources, Heroku might terminate your dynos. Optimize your code and consider scaling your dynos accordingly.
  • Heroku Logging: Actively check the Heroku logs to debug any problems during deployment and runtime. This will help identify unexpected errors or performance bottlenecks.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

Exactly! Skip the document manipulation entirely. Handle the game logic through Discord messages instead. Use message collectors or listen for user replies to capture their guesses. That’s the Discord way - no HTML elements needed.

You’re mixing browser code with Node.js - that’s why it’s breaking. Discord bots run server-side, so there’s no DOM to work with. I made this same mistake when I started - grabbed some web tutorial and couldn’t figure out why nothing worked. Skip the DOM stuff entirely. Use a Map or simple variables to track your game state instead. When someone hits !NumberGame, generate the random number and store it with their user ID as the key. Then just listen for their next message, compare it to your stored number, and fire back ‘too high’ or ‘too low’ with message.reply(). Way cleaner than trying to fake a webpage.

yeah, discord bots can’t access the document object - they’re not running in browsers. just use variables to track your game state and send regular discord messages instead of trying to update html elements that don’t exist.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.