9c9db344df1b4c4f8bef199a7053041812b7649d
Voter-Uptime-Bot
A Discord bot that monitors the availability of web services and reports uptime statistics directly in your server. Built with discord.py, aiohttp, and pydantic-settings, it goes beyond simple HTTP checks — detecting Cloudflare intercept pages and validating real page content so you know your sites are genuinely reachable, not just returning a 200.
Features
- Periodic polling — checks all configured sites every 15 minutes
- Cloudflare intercept detection — identifies challenge/block pages that return HTTP 200 but serve no real content
- Keyword content validation — confirms expected strings are present on the loaded page
- Retry logic — re-attempts checks on transient CF intercepts before marking a site degraded
- Uptime history — stores all check results in a local SQLite database
- Discord slash commands — view live status, 24-hour bars, and monthly summaries per site
Commands
| Command | Description |
|---|---|
/uptime now |
Current status of all monitored sites |
/uptime day <site> |
24-hour bar chart (🟩🟨🟥) with uptime % |
/uptime month <site> |
Current month summary, one square per day |
/uptime summarize |
Monthly uptime % for all sites at once |
Project Structure
app/
├── __init__.py
├── bot.py # Discord client, slash commands, polling task
├── checker.py # SiteChecker — HTTP, CF detection, keyword validation
├── config.py # Pydantic Settings — loads all config from .env
├── db.py # SQLite init, insert, and fetch helpers
└── utils.py # check_site wrapper, bar rendering, uptime maths
Configuration
All configuration is managed via a .env file using pydantic-settings. Copy .env.example to .env and fill in your values.
DISCORD_SECRET_KEY=your-bot-token-here
DISCORD_CLIENT_ID=123456789
DATABASE_PATH=uptime.db
MONITORED_SITES='[
{
"name": "MySite",
"url": "https://example.com",
"timeout_seconds": 10,
"expected_keywords": ["Login", "Vote"],
"max_retries": 1
}
]'
Site config fields
| Field | Required | Default | Description |
|---|---|---|---|
name |
✅ | — | Display name used in Discord |
url |
✅ | — | Full URL to check |
timeout_seconds |
10 |
Request timeout | |
expected_status |
200 |
Expected HTTP status code | |
expected_keywords |
[] |
Strings that must appear in the page body | |
max_retries |
1 |
Extra attempts on CF intercept before marking degraded |
How Checks Work
Each poll goes through three layers:
- HTTP status — non-2xx/3xx responses are marked degraded or down
- Cloudflare detection — response body is scanned for CF challenge fingerprints; a match is marked
degradedeven if status was 200 - Keyword validation — any
expected_keywordsthat are missing from the body mark the sitedegraded
Results are stored with a detection_reason (cf_intercept, missing_keywords, http_503, timeout, etc.) so you can query historical failure causes.
Result States
| State | Emoji | Meaning |
|---|---|---|
up |
🟩 | HTTP OK, no CF intercept, all keywords present, latency < 3s |
degraded |
🟨 | Reachable but CF intercept, missing content, slow, or 5xx |
down |
🟥 | Timeout, connection failure, SSL error, or unexpected status |
Installation
pip install -r requirements.txt
Run the bot:
python -m app.bot
Requirements
- Python 3.11+
- A Discord bot token with the
applications.commandsscope andbotscope enabled - The bot must be invited to your server with slash command permissions
Languages
Python
100%