A client who can see their own status on their own site or portal opens fewer tickets asking whether something is down. OctoPing publishes every status page as JSON, so you can read it and show the result wherever your client already looks. This guide reads the JSON on your server and renders it on a page.
What you need
- A published status page with the sites or heartbeats you want to show. Only published pages are available as JSON.
- Node.js 18 or later for the example, though any server-side language that can make an HTTP request works.
- A page on your own site to put the result on.
Read the status page and show it
Find the slug
Open the status page's settings. The Slug field under Basic Information is the last part of the page's address,
/status/{slug}. You need it for the request.Request the JSON
The address needs no key or login. Replace the slug with yours.
bash curl -fsS https://octoping.com/api/status-pages/YOUR_SLUG/publicPick the fields you need
The response is the same data OctoPing's own page renders. Most pages need only
overall_status, theitemsand theactive_incidents. This response is shortened: the ids are replaced and the appearance fields are left out.GET /status-pages/{slug}/public (shortened). The 3.33 uptime is low because this heartbeat was only minutes old { "name": "Acme status", "slug": "acme-status", "overall_status": "operational", "items": [ { "id": "00000000-0000-0000-0000-000000000001", "display_name": "Nightly backup", "item_type": "heartbeat", "current_status": "operational", "uptime_percentage": 3.33, "average_response_time": null, "daily_status": [] }, { "id": "00000000-0000-0000-0000-000000000002", "display_name": "Acme website", "item_type": "webpage", "current_status": "unknown", "uptime_percentage": null, "average_response_time": null, "daily_status": [] } ], "active_incidents": [], "recent_incidents": [], "scheduled_maintenance": [], "last_updated": "2026-11-07T04:54:41.751Z", "subscriptions_open": true }Make the request from your server
A script on another website can't read this address from the visitor's browser. The API allows browser requests only from octoping.com, so the browser blocks the rest. Make the request on your server, keep a copy for a minute and give your own page a small answer. This Node.js server does that and keeps showing the last good copy if OctoPing can't be reached.
status.mjs import { createServer } from "node:http"; const API = process.env.OCTOPING_API ?? "https://octoping.com/api"; const SLUG = process.env.STATUS_SLUG ?? "your-slug"; const CACHE_MS = 60_000; let cached = null; async function loadStatus() { if (cached && Date.now() - cached.at < CACHE_MS) return cached.body; let page; try { const res = await fetch(`${API}/status-pages/${SLUG}/public`, { signal: AbortSignal.timeout(5000), }); if (!res.ok) throw new Error(`OctoPing answered ${res.status}`); page = await res.json(); } catch (error) { if (cached) return cached.body; // keep showing the last good copy throw error; } const body = { overall: page.overall_status, updated: page.last_updated, items: page.items.map((item) => ({ name: item.display_name, status: item.current_status, uptime: item.uptime_percentage, })), incidents: page.active_incidents.map((incident) => incident.title), }; cached = { at: Date.now(), body }; return body; } createServer(async (req, res) => { if (req.url !== "/status.json") { res.writeHead(404).end(); return; } try { const body = await loadStatus(); res.writeHead(200, { "Content-Type": "application/json" }).end(JSON.stringify(body)); } catch { res.writeHead(503, { "Content-Type": "application/json" }).end(JSON.stringify({ error: "status unavailable" })); } }).listen(3030);Render it on your page
Your page asks your own server for
/status.jsonand writes the result into the page. UsingtextContentkeeps a name with an angle bracket in it from turning into markup.A list of items on any page <ul id="status">Loading status...</ul> <script> const labels = { operational: "Operational", degraded: "Degraded", down: "Down", maintenance: "Under maintenance", unknown: "Unknown" }; fetch("/status.json") .then((res) => res.json()) .then((page) => { const list = document.getElementById("status"); list.replaceChildren( ...page.items.map((item) => { const li = document.createElement("li"); li.textContent = `${item.name}: ${labels[item.status] ?? item.status}`; return li; }), ); }) .catch(() => { document.getElementById("status").textContent = "Status is unavailable right now."; }); </script>
Start the server with your own slug and open the page it serves from.
STATUS_SLUG=your-slug node status.mjsTurn the values into words
Show your own wording or copy the words OctoPing uses. The banner status has four values.
| overall_status | Shown on OctoPing as | Rule |
|---|---|---|
major_outage | Major Outage | At least one item is down. |
degraded | Some Systems Degraded | No item is down and at least one is degraded. |
maintenance | Under Maintenance | No item is down or degraded and at least one is under maintenance. |
operational | All Systems Operational | Everything else. |
Each item has one of these values in current_status.
| current_status | Shown as | From |
|---|---|---|
operational | Operational | Online and Partial |
degraded | Degraded | Degraded |
down | Down | Offline |
maintenance | Under maintenance | Maintenance |
unknown | Unknown | Pending and Disabled |
An active incident that marks a component down or degraded changes that item's status first, so the banner follows it. The status page JSON reference describes every field, including daily history, incidents and scheduled maintenance.
Verify it works
- Request your server's address. You should get the trimmed object, with the same overall status and items as the status page.
- Open your page and compare the list with the OctoPing status page for the same slug.
- Use a slug that doesn't exist. OctoPing answers HTTP 404, your server has no copy yet and answers 503, and the page shows its fallback text.
$ curl -s localhost:3030/status.json
{"overall":"operational","updated":"2026-11-07T04:54:41.751Z","items":[{"name":"Nightly backup","status":"operational","uptime":3.33},{"name":"Acme website","status":"unknown","uptime":null}],"incidents":[]}Respect the cache
OctoPing caches each status page for 60 seconds. A change an operator makes to the page or its incidents clears the cached copy, but the status of a monitored item can be up to 60 seconds behind. The last_updated field says when the copy was built. Keeping your own copy for the same 60 seconds means most visitors get your cached copy without waiting on OctoPing, and it keeps your server under the limit on requests from one address. A request over that limit gets HTTP 429.
Read the reference for Status page JSON
Last reviewed
Related
- DocsStatus page JSONRead a published status page and its incident history as JSON: the fields, pagination, caching and error responses.
- FeatureWhite-label status pages with custom domains and subscribersPublish a status page in your client's branding, with incidents, scheduled maintenance, email subscribers, feeds and client contacts. Custom domains on paid plans.
- DocsStatus pagesCreate, brand and publish a status page, choose what it shows and run an incident from first update to resolution.