A status badge that's safe to put on any website
2026-10-26
A status badge is a small piece of your monitoring that you hand to strangers. It renders on your marketing site, in a README or on a customer portal, for anyone who loads the page. So the questions to ask about it are mostly about what it doesn't do: what it leaks, what it lets someone guess, and what happens when it's switched off.
Archer is okokumo's badge. The first-check guide gives it one paragraph. This post goes through the code behind it.
The snippet
Open a check, expand Archer — public status badge, switch on Enable public status badge, then pick a style and a theme. The dashboard builds the snippet for you:
<iframe src="https://app.okokumo.com/embed/YOUR_TOKEN?variant=compact&theme=light" width="160" height="190" style="border:none;" title="Status badge"></iframe>
Choosing Detailed (30-day bar) changes it to variant=detailed at
width="520" height="140". Dark changes it to theme=dark. That's the whole
option set. Any theme other than dark renders light, and any variant
other than detailed renders the compact ring.
Archer is on every paid plan. On Free, the enable call returns 403 Archer requires a paid plan.
The token is the credential
The route is GET /embed/:token on the API, with no session and no API key. A
site embedding your badge couldn't send either. The token is 16 bytes from
crypto/rand, hex-encoded to 32 characters, and it is minted the first time
you enable the badge. Heartbeat ping URLs are built the same way.
The token addresses one check's badge and nothing more. It can't be used
against /v1, and it isn't included in your data export.
The export code says so explicitly: ping and embed tokens are "live credentials
that address a check publicly", not configuration you need in order to move.
Unknown and disabled look the same
The handler does one lookup: a check whose embed_token matches and whose
embed_enabled is true. If either condition fails, the response is the same
404 with the same unknown badge message.
That's deliberate. If a disabled badge answered differently from a token that
never existed, every 404 would tell an attacker which guesses had once been
real. With identical answers there's nothing to learn from probing, and the
token space is 2¹²⁸ anyway. The route is also rate-limited per IP to 60
requests a minute, with a 429 and Retry-After past that.
The one route built to be framed
Pages that hand out access are the usual clickjacking targets. okokumo's OAuth
consent screen sends X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none', because a framed Approve button would give an access
token to whoever framed it.
The embed route is the opposite case. Its only job is to be loaded inside
someone else's <iframe>, so it must never carry either header. The comment
on the route's registration says it "must NEVER be wrapped in frame-blocking
middleware", and a regression test fails the build if the handler ever sets
X-Frame-Options or a frame-ancestors directive.
Caddy passes /embed/* straight to the Go API without adding any frame
headers.
Being safe to frame is easier when there's nothing on the page to act on. The badge has no forms, no buttons, no JavaScript and no session. Its only interactive element is the footer link.
What a visitor sees
The page is a hand-built HTML string, without a template engine or a build step. It contains:
- The check's name, HTML-escaped. This is your check name exactly as it
appears in the dashboard, so rename
prod-api-lb-healthzto "API" before you embed it. - Compact: a 96 px ring. Its colour is the check's current state (green
up, red down, grey unknown), and the label inside is 30-day uptime with one
decimal, e.g.
99.9%. - Detailed: 30 squares, one per UTC day, oldest on the left. Each is up, down, partial (amber) or no data (grey). This variant shows no percentage.
- A footer: the okokumo mark and "Powered by Okokumo", linking to
https://okokumo.com/?ref=archer-badgein a new tab.
The page doesn't show the URL or host being checked, the check type, the interval, response times, error messages, alert channels or your organization name.
The percentage is successful probes divided by all probes over the last 30 UTC
days, today included. What "99.9% uptime" actually
counts works through the arithmetic,
including why a 3-minute outage still rounds to 100.0% on a badge. A check
with no results anywhere in the window shows – rather than 0% or 100%.
The two themes use the dashboard's own colours in dark (#0f1419 background,
#4ade80 up, #f7768e down). Light uses deeper shades (#16a34a, #dc2626,
amber #d97706), because a filled shape on white needs more contrast than
pastel text on near-black.
Paused means paused, nothing more
A check can be paused by hand or automatically after a plan downgrade, and the
dashboard records which. The badge shows neither. A paused check renders its
name and one neutral line, Monitoring paused. The compact ring goes grey
with – in place of the percentage. It isn't red, because a pause isn't an
outage. It isn't green either, even if the last recorded state was up.
The detailed bar keeps the days recorded before the pause. Paused days have no
results, so they're grey. A test sets the pause reason to plan_downgrade and
fails if that string ever appears in the response. Your visitors don't need to
know why you paused monitoring, and they won't learn whether it had anything to
do with billing.
Caching
A successful response carries Cache-Control: public, max-age=60, so a state
change can take up to about a minute to show. The 404 is returned before that
header is set and carries no cache header at all.
Disabling, and rotation
Switching the toggle off sets embed_enabled to false. From the next uncached
request, every copy of the snippet, wherever it was pasted, gets the same 404
as a token that never existed. In the browser, the frame shows a one-line JSON
error instead of your badge, so remove the snippet too.
The token itself is kept, so switching the badge back on brings back the same URL, and you don't have to find and re-paste every embed. Downgrading to Free does the same: it disables every badge in the organization and keeps the tokens. Re-upgrading and switching a badge back on restores its old URL.
There's no button to rotate the token yet. Today the only way to kill a URL is to switch the badge off, and switching it back on revives that same URL. The exposure is a read-only view of a name and a status, but if you want a URL that's no longer in circulation, that's a fair thing to want and we've noted it.
For more than one check, with incidents and 90 days of history, use Tower, on Pro and Business. Your status page is not a dashboard covers what belongs on one.