No data showing
Your bot is running fine, but the dashboard says "—" or the status stays grey. Walk this checklist top-to-bottom.
The most common operator issue. The bot is up locally, but the CloudLine dashboard shows grey status and — in every metric tile. Run through this checklist in order — each step is a different cause, ordered from most-common to least-common.
1. Are heartbeats reaching CloudLine at all?
Look at your bot's stdout / process logs. The SDK is intentionally quiet on success — it only logs when something fails. The four messages it can emit are:
CloudLine: heartbeat rejected (401) — check botId/secret
CloudLine: heartbeat HTTP <code>
CloudLine: heartbeat network error <…>
CloudLine: global fetch unavailable — Node 18+ required (or polyfill fetch)If you see any of these, the problem is on the network side — see the matching section below.
If you see none of these and the status is still grey, the SDK isn't running at all. Go to step 4.
2. 401 — check botId/secret
The most-common cause. Your bot is talking to CloudLine, but the secret is wrong.
Run through these in order:
- Did you rotate the secret on the dashboard recently? The new value invalidates the old one immediately. You must redeploy with the new value.
- Is the env var name right? The SDK reads whatever you pass to it; if you wrote
process.env.CLOUDLINE_TOKENand the var isCLOUDLINE_SECRET, the SDK getsundefinedand the request fails. - Did you swap botId and secret? The botId is short (
bot_…); the secret is long (clb_live_…+ 32 chars). The SDK fails fast on missing fields, but it can't tell you swapped them. - Is your env file actually being loaded? PM2, Docker, and systemd all have ways to strip
.envfiles. Verify by adding a one-timeconsole.log(process.env.CLOUDLINE_SECRET?.slice(0, 12))near the start of your bot — you should seeclb_live_…. Remove the log after you've confirmed.
3. heartbeat network error or HTTP 5xx
Your bot can't reach the CloudLine API:
- Egress firewall on your host blocking outbound HTTPS to
cloudline.kescohhtwitch.workers.dev. Some shared hosts default to deny-all egress except for whitelisted destinations. - DNS misconfiguration —
nslookup cloudline.kescohhtwitch.workers.devfrom the host should resolve to a Cloudflare IP. If it doesn't, your DNS resolver is broken. - Transient outage on Cloudflare or our Worker —
5xx. The SDK retries twice automatically (250 ms, 500 ms). If it persists, check status.cloudflare.com. - TLS / certificate failure on a very old Node runtime. Node 18+ ships with a fresh CA bundle; older versions can fail TLS handshakes against modern Cloudflare endpoints.
4. Status stays grey, no SDK logs
The heartbeat loop isn't running. The most common reasons:
-
attach()ran afterclient.login()/bot.run(). Both block-or-block-equivalent.bot.run()in Python doesn't return until the bot stops, so any code after it is unreachable. The SDK never started. -
attach()is in code that never executes. A condition was false, an import failed, an exception was swallowed. Add aconsole.log('cloudline attach')right after the call to confirm it runs. -
You used the manual constructor (
new CloudLine(…)) but never called.start(). Manual mode is opt-in. Either callstart(), or useattach()for the one-line version. -
You passed a bare
discord.Client(Python) instead ofcommands.Bot. Bare clients have noadd_listener, so the SDK can't hook events. The logger warns about this when it happens:CloudLine: client has no add_listener (bare discord.Client) — auto-start and command timing are disabled.Fix by switching to
commands.Bot/AutoShardedBot, or by using manual mode.
5. Status goes green, but tiles show —
The bot is heartbeating but not sending those specific metrics. Per-metric causes:
| Metric | Tile shows — because... |
|---|---|
| RAM / CPU (Python) | You installed cloudline-bot without the [metrics] extra. psutil is missing. Run pip install "cloudline-bot[metrics]". |
| RAM / CPU (other runtimes) | The runtime doesn't expose process.memoryUsage() or equivalents. The bot keeps working; the tile stays blank. |
| Slash p50 / p95 | No slash commands have been invoked yet in this heartbeat window. Trigger one. Percentiles are sampled-when-used, not polled. |
| Component p50 / p95 | Same — no button or select-menu interactions yet. |
| Autocomplete p50 / p95 | Same — autocomplete fires per keystroke. Type into a slash-command field that has autocomplete. |
| Latency (gateway ping) | discord.js reports -1 before the first heartbeat ack; discord.py reports NaN. The SDK normalizes both to null until the gateway settles. Usually clears within the first 10–30 seconds. |
| Event-loop lag (Deno) | Needs --unstable-node-builtins. Without it, perf_hooks isn't available. |
| Shards | Single-process bots intentionally report null so the dashboard's sharded tile stays silent unless the bot is genuinely sharded. |
6. Verifying the wire manually
When the SDK and logs aren't enough, send a hand-crafted heartbeat and see what the API says:
curl -X POST \
-H "Authorization: Bearer clb_live_yoursecret…" \
-H "Content-Type: application/json" \
-d '{"seq":1,"sent_at":'$(date +%s%3N)'}' \
https://cloudline.kescohhtwitch.workers.dev/api/bots/YOUR_BOT_ID/heartbeatPossible responses:
200 OKwith empty body — the credentials are valid and the server accepted the heartbeat. Refresh the dashboard; the status should turn green within seconds. If it does, your local SDK setup is the problem (likely step 4).401 Unauthorized— the secret is wrong, the bot doesn't exist, or it belongs to a different user. The 401 is intentionally indistinguishable between those three to prevent enumeration. Re-check both the botId and the secret.429 Too Many Requests— you're rate-limited from this IP. Wait 60 seconds and try again. In production this only fires under abuse; if you're hitting it with a single manual curl, your IP is shared with a noisy neighbor.
Still stuck?
Drop into the Discord support channel with your bot ID (safe to share) and the SDK log line. The team usually replies within a few hours.