Guide

Show live status on your own site

Goal

Show a client's live status inside your own website, portal or dashboard by reading their status page as JSON.

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

  1. 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.

  2. 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/public
  3. Pick the fields you need

    The response is the same data OctoPing's own page renders. Most pages need only overall_status, the items and the active_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
    }
  4. 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);
  5. Render it on your page

    Your page asks your own server for /status.json and writes the result into the page. Using textContent keeps 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.

bash
STATUS_SLUG=your-slug node status.mjs

Turn the values into words

Show your own wording or copy the words OctoPing uses. The banner status has four values.

overall_statusShown on OctoPing asRule
major_outageMajor OutageAt least one item is down.
degradedSome Systems DegradedNo item is down and at least one is degraded.
maintenanceUnder MaintenanceNo item is down or degraded and at least one is under maintenance.
operationalAll Systems OperationalEverything else.

Each item has one of these values in current_status.

current_statusShown asFrom
operationalOperationalOnline and Partial
degradedDegradedDegraded
downDownOffline
maintenanceUnder maintenanceMaintenance
unknownUnknownPending 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.
Output from the server above (the uptime is low because the heartbeat was only minutes old)
$ 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

Stop finding out last.

Add a site, pick which of the eight checks matter, and get on with your day. The trial is free for 14 days and needs no card.