Skip to contentOutRay/Docs
GitHub ↗
Get started ↗
Documentation

Your services, from local to live.

OutRay documentation

Products

UptimeCreate your first monitorMonitor checks and publishing rulesDetections, drafts, and incidentsConfigure a status pageHeadless status pagesTeam and subscriber notifications
Uptime

Headless status pages

Build a custom frontend with public status data, email subscriptions, and optional visitor analytics.

OutRay can provide the status data while you build and host the frontend. Every published page includes the public data API, including on Free. Your OutRay-hosted page remains available alongside your custom frontend.

Open Uptime → Status pages, select a page, and click the Headless button to open its setup panel with exact API URLs and the optional analytics snippet. Publish the page before fetching data. You do not need a CNAME change, an API key, or an OutRay-managed certificate for your own frontend.

Fetch public status

const response = await fetch(
  "https://status.outray.app/api/v1/pages/YOUR_PAGE_ID"
);
if (!response.ok) throw new Error("Status temporarily unavailable");
const page = await response.json();
console.log(page.state, page.groups, page.standaloneComponents);

The dashboard supplies the correct endpoint URLs. The page ID is public and is not a secret. Browser fetches need no cookies or authorization headers; cross-origin reads are supported.

Response fields

FieldMeaning
id, slug, name, descriptionPublic page identity and copy
logoUrl, accentColor, canonicalUrlBranding and the OutRay-hosted address
subscriptionsEnabledWhether visitors can request email updates through either the hosted page or headless API
stateoperational, degraded, outage, or unknown
generatedAtISO-8601 timestamp when the response was generated
groupsOrdered groups, each containing its state and ordered components
standaloneComponentsOrdered components outside groups; use sortOrder to interleave them with groups
incidentsUp to 25 published incidents, with active incidents first, then newest first

Each component contains id, name, description, sortOrder, state, manual, updatedAt, observedUptime90d, and history. History contains 90 UTC days with observed check counts, failure/incident minutes, and public incident references. Missing evidence remains unknown, not invented uptime. observedUptime90d is a percentage, or null when no measured evidence is available.

Incidents include their public title, lifecycle status (open or resolved), published stage, affected component names, timestamps, latest note, and published updates. Each update contains id, note, structured body, status, and publishedAt. Timestamps are ISO-8601 strings or null. Render notes as text; render structured incident bodies with a safe renderer rather than injecting untrusted HTML.

For a complete individual incident report, including an incident outside the overview's latest 25:

GET https://status.outray.app/api/v1/pages/YOUR_PAGE_ID/incidents/INCIDENT_ID

Only data already eligible for the public hosted page is exposed. Hidden components/groups, private updates, subscriber information, organization IDs, and monitor configuration are not included.

Refresh and errors

Poll every 60 seconds. Successful responses are publicly cached for 15 seconds. A successfully fetched page returns HTTP 200 even when state is outage; read the JSON state instead of treating HTTP status as service health.

Missing or unpublished pages and unavailable/private incidents return 404 with {"error":"not_found"}. Data-loading failures return 503 with {"error":"status_unavailable"} and are not cached. Never present a failed fetch as “all systems operational.” Unpublishing removes API access, subject to the existing 15-second public cache window.

Optional visitor analytics

Analytics is available on paid plans. It is not required to use the public JSON API.

  1. Under Headless → Allowed websites, register each exact origin, such as https://status.example.com. Up to 10 are supported. Do not include a path, query, wildcard, or credentials. Origins include their port; registering the apex does not authorize subdomains.
  2. Save the list, then include the snippet from your dashboard on your custom status frontend:
<script defer
  src="https://status.outray.app/status-tracker.v1.js"
  data-page-id="YOUR_PAGE_ID"></script>

For a page at https://example.com/status, register https://example.com and install the script only on the status frontend. The script tracks whichever page paths it is installed on; it is not a general application analytics SDK.

The tracker counts visible initial loads, pathname changes from pushState, replaceState, or browser back/forward navigation, and back/forward cache restoration. Query-only and hash-only changes are not new views. Duplicate copies of the snippet do not duplicate tracking for the same page. You do not need a framework adapter or npm package.

Views are combined with hosted-page visits in Analytics, using your existing plan's retention period. Removing an allowed origin, unpublishing the page, or losing paid access stops custom-page collection. Origin restrictions are browser-side abuse protection, not proof against a client deliberately forging HTTP headers.

The script uses credential-free requests, no cookies or browser storage, and sends no query strings or fragments. Referrers retain only their hostname; same-site referrers are excluded. Raw IP addresses and user agents are not stored. Visitor estimates rotate daily. DNT, Global Privacy Control, known bots, and speculative page loads are excluded. Analytics failures never block your frontend.

HTTP localhost origins are accepted only for development installations, not hosted production. Use the local status-service URL shown in the development dashboard.

Content Security Policy

If your frontend uses CSP, add your status-service origin to script-src and connect-src, retaining your existing directives:

script-src 'self' https://status.outray.app;
connect-src 'self' https://status.outray.app;

No wildcard origins or unsafe-inline are needed for this integration.

Email subscriptions

Build your own email form using the public subscription endpoint. It is available on every plan, independently of paid analytics and the analytics allowed-website list. Show the form only when the page's subscriptionsEnabled field is true.

const response = await fetch(
  "https://status.outray.app/api/v1/pages/YOUR_PAGE_ID/subscribe",
  {
    method: "POST",
    credentials: "omit",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email: "[email protected]" }),
  }
);
if (!response.ok) throw new Error("Could not request subscription");
// Show: "Check your inbox to confirm your subscription."

Use your configured status-service origin, as with the data API. Browser requests support cross-origin JSON and OPTIONS preflights; no cookies, authorization, or browser secret is required. Add that origin to your frontend's connect-src CSP directive. Non-browser clients may use the same endpoint.

A successful request returns HTTP 200 with {"ok":true}. This is an acknowledgement, not proof of delivery or an active subscription. New subscribers must confirm through the emailed link, which expires after 24 hours. The existing hosted confirmation and unsubscribe pages handle consent; API requests never bypass confirmation or return a confirmation token.

Hosted and headless forms share subscriber quotas and per-page rate limits: up to five requests per IP per hour and one per email per 15 minutes. Already subscribed, throttled, full, and temporarily undeliverable addresses receive the same acknowledgement, so the endpoint does not reveal subscription status. Do not retry successful requests automatically or poll this endpoint.

Requests accept only JSON objects with an email string, with a maximum body size of 4 KiB. Errors are JSON and are never cached:

HTTP statuserrorMeaning
400invalid_subscription or invalid_emailInvalid JSON, missing email, or invalid email address
404not_foundInvalid, missing, or unpublished page
409subscriptions_disabledThe page owner has paused subscriptions
413payload_too_largeBody exceeds 4 KiB
415unsupported_media_typeContent-Type must be application/json
503status_unavailableThe service or page lookup is unavailable

Alternatively, link visitors to the canonicalUrl returned by the data API to use the hosted form. Existing subscribers, confirmation emails, incident updates, and unsubscribe links work the same way regardless of which form was used. See status page notifications.

Configure a status page

Choose public components, appearance, publishing, and a verified custom subdomain.

Team and subscriber notifications

Configure team destinations and distinguish them from public status-page subscriber delivery.

On this page

Fetch public statusResponse fieldsRefresh and errorsOptional visitor analyticsContent Security PolicyEmail subscriptions