> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kodostatus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Status Widget

> Embed a live status indicator on any website

Drop a single `<script>` tag into your site to show live status from your
Kōdo status page. The widget respects your page's brand color, auto-refreshes,
and surfaces active incidents inline.

<Note>
  `widget.js` is a **floating overlay** (badge, banner, or corner pill). To
  render a full status panel **inline** in your layout — with per-component
  uptime and a Shadow-DOM you can theme — use the
  [Status Element](/integrations/status-element) (`<kodo-status>`) instead.
</Note>

## Quick start

```html theme={null}
<script src="https://kodostatus.com/widget.js"
        data-page="your-page-slug"
        data-style="badge"
        defer></script>
```

Replace `your-page-slug` with the slug of a **public** status page. The script
inserts the widget directly after itself (except `floating`, which attaches
to `<body>`).

## Styles

### `badge` — pill indicator

A compact pill with a pulsing dot and status label. Inherits the page's
`primary_color` when operational; falls back to semantic colors (amber /
orange / red) during incidents.

```html theme={null}
<script src="https://kodostatus.com/widget.js"
        data-page="your-page-slug"
        data-style="badge" defer></script>
```

### `banner` — full-width strip

Horizontal banner meant for the top of a page or layout.

```html theme={null}
<script src="https://kodostatus.com/widget.js"
        data-page="your-page-slug"
        data-style="banner" defer></script>
```

### `floating` — fixed corner pill

Pinned to a corner of the viewport. Use `data-position` to choose:
`bottom-right` (default), `bottom-left`, `top-right`, `top-left`.

```html theme={null}
<script src="https://kodostatus.com/widget.js"
        data-page="your-page-slug"
        data-style="floating"
        data-position="bottom-right" defer></script>
```

### `incident` — live incident banner

Shows only when there is an active incident. Displays severity, phase,
time since last update, and the incident title. Great for app-top alert
bars that disappear when things are healthy.

```html theme={null}
<script src="https://kodostatus.com/widget.js"
        data-page="your-page-slug"
        data-style="incident"
        data-hide-when-operational="true" defer></script>
```

When `data-hide-when-operational="true"` (recommended), the widget renders
nothing while all systems are operational. If the attribute is omitted or
`false`, the widget falls back to a `banner` style when there is no active
incident.

## Attributes

| Attribute                    | Values                                                    | Default        | Description                                                     |
| ---------------------------- | --------------------------------------------------------- | -------------- | --------------------------------------------------------------- |
| `data-page`                  | string                                                    | *required*     | Public status page slug.                                        |
| `data-style`                 | `badge` / `banner` / `floating` / `incident`              | `badge`        | Widget variant.                                                 |
| `data-position`              | `bottom-right` / `bottom-left` / `top-right` / `top-left` | `bottom-right` | Floating-only placement.                                        |
| `data-theme`                 | `auto` / `light` / `dark`                                 | `auto`         | Theme preference for subtle shadow / contrast.                  |
| `data-hide-when-operational` | `true` / `false`                                          | `false`        | `incident` style only — hide entirely when no active incidents. |

## Programmatic API

The widget dispatches a `kodo:status-change` custom event on `window`
whenever overall status changes between polls:

```js theme={null}
window.addEventListener('kodo:status-change', (e) => {
  console.log(e.detail);
  // {
  //   slug: 'your-page-slug',
  //   status: 'major_outage',      // new status
  //   previousStatus: 'operational',
  //   activeIncidents: [ { id, title, severity, status, ... } ],
  //   snapshot: { /* full StatusSnapshot */ },
  // }
});
```

Use this to trigger toast notifications, Sentry breadcrumbs, or in-app
banners without rendering the widget itself.

## Branding

The widget automatically reads the following from your status page:

* `primary_color` — used as the operational background
* `theme_mode` — currently influences shadow weight; expanded theming is planned

To change these, edit your status page in the dashboard under
**Status Pages → your page → Appearance**.

## Refresh behaviour

The widget connects to a **server-sent events** stream and receives new
snapshots as soon as the server detects a change (within \~5 seconds of
the event). If the browser does not support `EventSource`, or the stream
fails before the first snapshot arrives, the widget transparently falls
back to polling every 60 seconds.

Each SSE connection is capped at \~55 seconds and then gracefully rotated
— the client reconnects automatically with no visible flicker.

## Server-sent events endpoint

If you want to build your own live widget, subscribe to:

```
GET https://kodostatus.com/api/public/status/{slug}/stream
```

The stream emits these named events:

* `snapshot` — the full `StatusSnapshot` JSON, sent on connect and again
  whenever the snapshot changes
* `reconnect` — sent just before the server closes the stream so the
  client can reconnect for another window
* `error` — sent with `{ "message": "not_found" }` if the slug is invalid

Example:

```js theme={null}
const es = new EventSource(
  'https://kodostatus.com/api/public/status/acme/stream'
);
es.addEventListener('snapshot', (e) => {
  const snap = JSON.parse(e.data);
  console.log(snap.status, snap.activeIncidents);
});
```

## Accessibility

The widget root is rendered with `role="status"` and `aria-live="polite"`,
so screen readers announce status changes without stealing focus. All
user-supplied strings (incident titles, etc.) are HTML-escaped.

## Public API

The widget is a thin wrapper around this endpoint — you can build your own
widget against it:

```bash theme={null}
curl https://kodostatus.com/api/public/status/your-page-slug
```

Response:

```json theme={null}
{
  "organization": { "name": "Acme", "slug": "acme" },
  "branding": {
    "primaryColor": "#22c55e",
    "logoUrl": "https://.../logo.png",
    "hideBranding": false,
    "themeMode": "system"
  },
  "status": "operational",
  "services": [
    { "id": "...", "name": "API", "status": "operational", "display_order": 0 }
  ],
  "activeIncidents": [],
  "lastUpdated": "2026-04-14T12:34:56.000Z"
}
```

CORS is enabled for all origins. Responses are cached at the edge for 30
seconds.

## Content Security Policy

If your site uses CSP, allow the widget source and API origin:

```
script-src 'self' https://kodostatus.com;
connect-src 'self' https://kodostatus.com;
```
