close

DEV Community

John Wick
John Wick

Posted on

Creating a Live Status Page for Your Python Bot

Building a Live Status Dashboard for Your Python Bot

A JSON health check is enough for a hosting platform, but it's not much use to you when you want a quick, human-readable view of whether your bot is actually doing its job. This guide covers building a real python bot status dashboard — with proper HTML, CSS, and a bit of JS — using nothing more than StayPresent's web.html() and the HTTP server it already runs.

Table of Contents

  1. Why a Dashboard Beats a JSON Blob
  2. How web.html() Works
  3. Serving Static Assets Alongside HTML
  4. Writing Data From Your Bot to the Dashboard
  5. A Complete Dashboard Example
  6. Auto-Refreshing the Page
  7. Security Considerations
  8. Best Practices
  9. Common Mistakes
  10. FAQs
  11. Conclusion

Why a Dashboard Beats a JSON Blob

staypresent.web.json({"status": "running"}) is perfect for a hosting platform's health check, but if you're the one checking on your bot at 1 a.m. from your phone, a formatted page — uptime, last-processed item, error count — is a lot faster to read than raw JSON. Since StayPresent's HTTP server already exists to satisfy the platform's port requirement, there's no reason not to make it genuinely useful to you too.

How web.html() Works

web.html() points StayPresent's root route at a file on disk, which is read fresh on every request:

import staypresent

staypresent.web.html("templates/dashboard.html")
staypresent.run("bot.py")
Enter fullscreen mode Exit fullscreen mode

Because the file is re-read each time rather than cached at startup, you can update dashboard.html from your bot's own code while it's running, and the next page load reflects the change — no restart required.

Serving Static Assets Alongside HTML

Any CSS, JS, or image files placed in the same directory as the target HTML file are automatically served too, with path traversal explicitly blocked for security:

templates/
├── dashboard.html
├── style.css
├── status.js
Enter fullscreen mode Exit fullscreen mode
<!-- templates/dashboard.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Bot Status</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>Bot Dashboard</h1>
  <div id="status">Loading...</div>
  <script src="status.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Writing Data From Your Bot to the Dashboard

Since web.html() just reads whatever is on disk, the simplest way to reflect live data is to have your bot script write a small JSON or HTML fragment to disk whenever its state changes, and have the dashboard read or fetch it:

# inside bot.py
import json

def update_status(processed_count, last_error):
    with open("templates/status.json", "w") as f:
        json.dump({
            "processed": processed_count,
            "last_error": last_error,
        }, f)
Enter fullscreen mode Exit fullscreen mode

Because status.json lives in the same directory as dashboard.html, StayPresent serves it automatically as a static file the dashboard's JS can fetch.

A Complete Dashboard Example

templates/dashboard.html:

<!DOCTYPE html>
<html>
<head>
  <title>Bot Dashboard</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>Bot Status</h1>
  <p>Processed: <span id="count"></span></p>
  <p>Last error: <span id="error"></span></p>
  <script src="status.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

templates/style.css:

body { font-family: sans-serif; background: #111; color: #eee; padding: 2rem; }
h1 { color: #4ade80; }
Enter fullscreen mode Exit fullscreen mode

templates/status.js:

async function refresh() {
  const res = await fetch("status.json");
  const data = await res.json();
  document.getElementById("count").textContent = data.processed;
  document.getElementById("error").textContent = data.last_error || "none";
}
refresh();
setInterval(refresh, 5000);
Enter fullscreen mode Exit fullscreen mode

main.py:

import staypresent

staypresent.web.html("templates/dashboard.html")
staypresent.run("bot.py")
Enter fullscreen mode Exit fullscreen mode

Auto-Refreshing the Page

The status.js example above polls status.json every five seconds via fetch(), which keeps the numbers current without a full page reload. For a simpler (if less smooth) approach, a meta refresh tag works too:

<meta http-equiv="refresh" content="10">
Enter fullscreen mode Exit fullscreen mode

Security Considerations

web.html() blocks path traversal internally, so requests can't escape the target directory to read arbitrary files on disk — but that protection only covers file access, not what you choose to put in the dashboard itself. Don't write secrets, API keys, or tokens into dashboard.html or any file served alongside it, since the route is public by default.

Best Practices

  • Keep the dashboard's data file (status.json or similar) small and write it atomically if your bot updates it frequently, to avoid the dashboard reading a half-written file.
  • Use web.get() during development to confirm what StayPresent currently has configured, independent of what's rendering in the browser:
current_state = staypresent.web.get()
# {"type": "html", "value": "templates/dashboard.html"}
Enter fullscreen mode Exit fullscreen mode
  • Keep the dashboard read-only. If you need the page to trigger actions against your bot, that's a separate concern from StayPresent's simple keep-alive responses.

Common Mistakes

  • Putting the HTML file in a different directory than its CSS/JS. Static asset serving only covers files in the same directory as the target HTML file.
  • Writing the status file from multiple threads without any coordination, risking a dashboard read landing mid-write. A simple write-to-temp-then-rename pattern avoids this.
  • Exposing sensitive internal state (API keys, database contents, raw error tracebacks) directly on a publicly reachable dashboard route.

FAQs

Can I use a JS framework instead of plain HTML/CSS/JS?
Yes — as long as the built output is static files in the target directory, StayPresent will serve them the same way.

Does the dashboard slow down the health check?
No — /health is a separate, dedicated route that always returns a fixed {"status": "ok"} regardless of what's configured at /.

Can I switch between JSON and HTML responses at runtime?
Yes — calling web.json() or web.html() again simply reconfigures the root route; there's no need to restart the server.

Conclusion

A python bot status dashboard doesn't need a separate web framework or hosting setup — staypresent.web.html() turns the same HTTP server your platform already requires into a genuinely useful, live-updating status page, with plain HTML, CSS, and JS doing all the work.

pip install staypresent[prod]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)