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
- Why a Dashboard Beats a JSON Blob
- How
web.html()Works - Serving Static Assets Alongside HTML
- Writing Data From Your Bot to the Dashboard
- A Complete Dashboard Example
- Auto-Refreshing the Page
- Security Considerations
- Best Practices
- Common Mistakes
- FAQs
- 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.jsonor 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
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.