Skip to main content

Status page by region

A status page's job is to answer one question in under two seconds: is the bit I use working? For anyone running in more than one region, a list of nine region names does not answer that as fast as nine coloured dots in the right places.

Loading globe…

The code​

import { createGlobe } from "canvas-globe";

const COLOR = { ok: "#22c55e", degraded: "#f59e0b", down: "#ef4444" };

function toMarker(region) {
return {
label: region.name,
lat: region.lat,
lon: region.lon,
color: COLOR[region.status],
live: region.status !== "ok", // only unhealthy regions pulse
latency: region.latency,
};
}

const globe = createGlobe(canvas, {
mode: "map",
preset: "blueprint",
projection: "naturalEarth",
autoRotate: false,
labels: "markers",
markers: regions.map(toMarker),
legend: {
title: "Region health",
items: [
{ color: COLOR.ok, label: "Operational" },
{ color: COLOR.degraded, label: "Degraded" },
{ color: COLOR.down, label: "Outage" },
],
},
showViewer: { label: "You" },
tooltip: (m) => (m.latency ? `${m.label}: ${m.latency} ms` : `${m.label}: no response`),
onClick: (m) => m && scrollToIncident(m.label),
});

// Refresh on the same cadence as your health checks.
setInterval(async () => {
const regions = await fetch("/api/status").then((r) => r.json());
globe.setMarkers(regions.map(toMarker));
}, 30000);

Why only the broken ones pulse​

live: true gives a marker a slow pulse. The instinct is to put it on everything, because it looks alive. Do not: if all nine pulse, none of them stand out, and you have built a decoration instead of a signal.

Keep healthy markers green, still, and small. Reserve motion, saturation, and size for the region that needs attention.

Colour is not enough​

Roughly one in twelve men cannot reliably separate your green from your red. A status page that encodes state only in hue fails exactly the people who most need it to work.

  • Keep the text list. The map is a summary of a table that is still on the page, in the DOM, readable by a screen reader and by anyone who prefers reading.
  • Vary size as well as colour. A down region can be a larger marker.
  • Use the label. With labels: "markers" the region name is on the map regardless of colour.
<ul class="regions">
<li><span data-status="ok">Operational</span> eu-west: 18 ms</li>
<li><span data-status="degraded">Degraded</span> eu-central: 187 ms</li>
<li><span data-status="down">Outage</span> sa-east: no response</li>
</ul>

See Accessibility for how the canvas exposes itself to assistive tech.

Latency instead of state​

If you are showing performance rather than uptime, drive the colour continuously and let the legend carry a scale:

import { colorScale } from "canvas-globe";

const latencyColor = colorScale([20, 250], ["#22c55e", "#ef4444"]);

markers: regions.map((r) => ({ ...r, color: latencyColor(r.latency) })),
legend: { title: "p95 latency (ms)", scale: { domain: [20, 250], range: ["#22c55e", "#ef4444"] } },

Pick the domain from your actual SLO, not from the data. A scale that rescales itself every refresh makes a good day and a bad day look identical.

Show them their region​

The most useful thing a status map can do is point at the region the visitor is actually served from. If you know it, say so:

globe.setViewerLocation({ lat: 51.47, lon: -0.45, label: "You are served from eu-west" });

If you do not, showViewer falls back to the visitor's time zone: no permission prompt, no request, and accurate enough to be useful at this zoom. See Viewer location.

Internal dashboards​

The same map on a wall screen wants different settings:

{
mode: "map",
preset: "midnight",
interactive: false, // nobody is going to drag a TV
labels: "markers",
fps: 15, // it will run for months
}

Add spikes keyed to request volume if the board also needs to answer "where is the traffic", and check Performance before leaving anything running indefinitely.

Next​

Talk to a real person

Live human support. Choose what you need help with.