@signalwire/status-widget

Platform status, anywhere on the site.

One dependency-free script reads the PagerDuty status feed and renders it two ways: a quiet dot and label for the site footer, or a full service dashboard. No framework, no build step, and nothing to keep running at request time.

signalwire.com footer, community column

01 / Footer indicator

The state a visitor actually needs

Four states and one failure state. A single degraded service does not read as a full outage, and a failed fetch renders neutral rather than a false green.

Simulate

live data
Upstream severityIndicatorCopy
all goodgreenAll systems operational
minorgoldSome systems degraded
majorredActive incident
maintenanceblueScheduled maintenance
fetch failedgreySystem status unreachable

02 / Full dashboard

Same script, same markup, any skin

The widget ships semantic markup and stable class names. Colour, type and spacing come from custom properties, so a host page restyles it without forking anything.

Theme

Simulate

Columns

dark / live data

03 / Install

Three ways in

Published to npm and mirrored on the SignalWire CDN, the same path the call widget uses.

<!-- CDN, no build step -->
<link rel="stylesheet"
  href="https://cdn.signalwire.com/@signalwire/
    status-widget/dist/swstatus.css">
<script src="https://cdn.signalwire.com/
  @signalwire/status-widget/dist/swstatus.js"></script>

<sw-status
  variant="footer"
  src="https://cdn.signalwire.com/signalwire/status-widget/main/data/snapshot.json"
  refresh="60"></sw-status>
// npm, for the Framer code component
// npm i @signalwire/status-widget
import SWStatus from '@signalwire/status-widget';
import '@signalwire/status-widget/swstatus.css';

SWStatus.mount(ref.current, {
  variant: 'footer',
  source: 'https://cdn.signalwire.com/signalwire/status-widget/main/data/snapshot.json',
  refresh: 60000
});
// headless, if you want to render it yourself
const state = SWStatus.derive(await SWStatus.load(url));
// { overall, headline, services[], active[], upcoming[], history[] }

04 / How the data arrives

No token, no receiver, one static file

The status page API is public and needs no credentials. The only real obstacle is CORS, and that is solved by mirroring rather than by building a service.

What is actually blocked

The four endpoints below answer unauthenticated requests. No API token is involved, so there is no credential to keep out of client-side code.

What they do not send is Access-Control-Allow-Origin. A preflight returns only Allow: GET,HEAD. That means a browser on signalwire.com cannot read them directly, no matter how the fetch is written.

The mirror

A scheduled job pulls the four endpoints and writes one merged snapshot.json. That file goes to static hosting that already sends Access-Control-Allow-Origin: *.

cdn.signalwire.com already does, on every response. So does raw.githubusercontent.com, which the bundled GitHub Action targets with no secrets.

Endpoints merged

/api/dataPage config, descriptions
/api/servicesService list
/api/post_enumsStatus vocabulary
/api/postsIncidents, maintenance
Why health is derived. Services carry no status field upstream. A service is operational unless an unresolved post lists it under impacts. The widget applies the worst active impact per service, then rolls those up to an overall state, matching the rule the PagerDuty dashboard itself uses.
Freshness is a scheduling question. The snapshot is only as current as the job that writes it. GitHub cron runs at a five minute floor and can be delayed. For incident-grade freshness, run the refresh on a shorter external schedule and keep the CDN cache TTL at 60 seconds.