Skip to content

Status Pages

A status page is the public face of your service health, a separate surface from the internal alert console where customers, partners, and stakeholders can see what’s working, what isn’t, and what you’re doing about it. This page explains the mental model end-to-end: what gets published, what stays internal, how visitors experience it, and the editorial control you keep.

Status page configuration settings

YipYap separates the internal alert stream from the public health surface on purpose. Two distinct planes:

  • Alerts are the firehose: every monitor state change, every flap, every escalation, every notification. Operators care about all of this. Customers don’t.
  • Status pages are the curated surface: a hand-picked set of monitors organised by what users actually care about, plus operator-authored incidents that explain disruptions in customer-facing language.

Nothing on the public status page is automatic except the monitor up/down badges. Incidents are publishable on demand, you decide when something is worth telling visitors about, what to call it, and when it’s resolved. A monitor flapping for ten seconds doesn’t need to become a public incident; a deploy that broke checkout for half an hour does.

Open https://console.yipyap.run/<your-org>/status/<page-slug> (no login required) and the page renders a single HTML document:

  1. Overall status banner at the top. Three colours: green (“All Systems Operational”), amber (“Partial / Minor / Degraded”), red (“Major System Outage”). The banner reflects the worst of:
    • The active set of in-flight incidents (severity-weighted), AND
    • The current state of the monitors on the page.
  2. Active incident timeline. Every unresolved incident linked to this page renders here, newest update first. Each shows title, severity, affected monitors (by name), and the running thread of operator-authored updates.
  3. Component groups. Your organisational sections, “API”, “Web App”, “Database”, each with the monitors you placed inside them. Per-monitor display is configurable: status badge, uptime bar, latency sparkline, recent check history, recent incidents inline.
  4. Recent resolved incidents. The trailing seven days of resolved incidents, collapsed by default, expandable.
  5. Custom CSS (if configured) restyles the rendered page. Sanitised server-side, no scripts, no external imports, no \ escape sequences.

The page is server-rendered HTML, fast on slow networks, and works without JavaScript for the vast majority of the layout. (Sparkline charts use a small client-side script when present.)

To set expectations correctly:

  • No subscribers. YipYap doesn’t currently send email/SMS/RSS updates to status-page visitors. Visitors who want updates check the page or watch their RSS reader against the page URL, there’s no opt-in subscription form. (If your stakeholders need push, route a copy of the incident-update events to a dedicated notification channel like Slack or webhook.)
  • No custom domains. Status pages live at console.yipyap.run/<org>/status/<slug>. There’s no CNAME or status.example.com mapping today.
  • No service-catalog components. Status pages display monitors. The service catalog is a separate internal-facing surface; services don’t render on public pages.
  • No private/auth-gated status pages. Every page is fully public to anyone with the URL. If a page is sensitive, don’t link to it externally, but understand the URL is enumerable if attackers know your org slug.
  • No free-form text components. Each item on the page is a monitor; descriptive text lives in the page-level description and per-monitor display name.

If any of these are blockers for your use case, raise it in the console feedback form, they’re tracked as feature requests.

The page assembles itself on every request. When a visitor opens /{org}/status/{slug}, the server-rendered handler looks up the page record, fetches its groups and the monitors inside each group, joins each monitor’s current state, pulls in the active and recently-resolved incidents linked to this page, computes the overall-status banner from the worst monitor state and incident severity, and renders a single HTML response with sanitised custom CSS injected at the top.

The monitor side updates continuously without operator action. The incident side is fully operator-driven: you create, update, and resolve incidents through the console (or the API), and you control which page each incident appears on via the link table.

  1. Settings → Status Pages → New Status Page.
  2. Name is the human-readable title that renders in the visitor’s tab and at the top of the page.
  3. Slug becomes the URL segment. Lowercase, alphanumeric, hyphens. Immutable once visitors have the link, pick something durable.
  4. Description renders under the title. Markdown is NOT supported; treat it as plain text.
  5. Custom CSS (optional) ships verbatim to the visitor’s browser, sanitised. See Custom CSS below for what’s allowed.
  6. Enabled toggle. When unchecked, visitors hitting the URL get a 404, useful to stage a page before announcing it.
  7. Save.

The page is now live but empty. Add groups + monitors next.

Status pages are organised into groups, labelled sections that contain monitors. A page with three groups (“API”, “Web App”, “Database”) displays as three sections. Reorder groups and the monitors inside them with the up and down arrow buttons in the layout editor.

Each group has:

  • Name, the section heading visitors see.
  • Default expanded, whether the section is open or collapsed on first visit. Useful when a group is rarely-relevant (e.g., legacy services kept for transparency).
  • Position, order on the page, top to bottom.

Each monitor on the page is added with display options:

OptionDefaultMeaning
display_nameemptyOverride the monitor’s internal name. Use this to make “checkout-prod-us-east-1” render as “Checkout API” to visitors.
show_statustrueRender the green/amber/red badge.
show_uptime_bartrueRender the rolling uptime bar (the column of green segments).
uptime_periods”30d”What window the uptime bar covers. Common values: 7d, 30d, 90d.
show_latencyfalseRender a tiny latency sparkline alongside status. Off by default, most users find it noisy on a status page.
show_checksfalseRender the most recent N check results inline. Mostly for debug pages.
show_incidentstrueShow this monitor’s recent incidents inline beneath its row.

Drag monitors between groups to re-organise. Monitors not assigned to any group render in an “Other” section above the named groups.

The badge a visitor sees on each monitor depends on the monitor’s current state. The mapping:

Monitor statePublic badge
Up”Operational” (green)
Degraded”Degraded Performance” (amber)
Down”Outage” (red)
Paused”Paused” (grey), monitor is intentionally off
MutedTreated as Up, muting hides alerts internally but the public sees normal status
Maintenance”Maintenance” (blue badge with the window’s description)
Custom statesMapped per state’s severity field, see Custom States

Maintenance is the one transition operators frequently miss: when a maintenance window covering a monitor is active, the public page shows a “Maintenance” badge (not red), and the page-level overall banner is unaffected. Without this mapping, planned deploys would publish as “Outage” on the public page, confusing and embarrassing.

Status pages display incidents, operator-authored, customer-facing records of disruptions. Distinct from alerts:

  • Alerts are internal pages/notifications driven by monitor state.
  • Incidents are public communications driven by operators.

You create an incident, link it to one or more status pages, mark which monitors it affects, and post updates. Visitors see the incident on every linked page until you mark it resolved.

The most common flow:

  1. An alert fires, your on-call gets paged, they investigate.
  2. The on-call decides this is customer-impacting and clicks Create incident on the alert detail page.
  3. YipYap pre-populates the incident with: title (from the alert summary), severity (mapped from alert severity), the affected monitor (linked).
  4. The on-call picks which status pages to link the incident to, types a customer-facing first update, and publishes.
  5. As the incident progresses, the on-call posts further updates (investigatingidentifiedmonitoringresolved). Each update shows on the public timeline; updates with public: false stay internal.

The whole flow is also available via the Incidents API, bridges to PagerDuty / Opsgenie / your own runbook tooling can use it directly.

When at least one active incident is linked to the page, the page-level banner reflects the worst severity:

Worst active severityBanner
Critical”Major System Outage” (red)
Major”Partial System Disruption” (amber)
Minor”Minor Service Degradation” (amber)

When no incidents are active, the banner is computed from monitors only (any down → red; any degraded → amber; otherwise green).

Each incident update has a public flag. Updates marked public appear on the status page; updates marked private stay in the console for the operator team. Use private updates for internal coordination (“rolling back via runbook X, ETA 5min”) and public updates for customer-facing communication (“we’ve identified the cause and are rolling back the deployment”).

Each status page accepts a block of CSS in the custom_css field. It is injected verbatim into the page’s <style> block on every render, after the default theme, so anything you write overrides the defaults via normal CSS cascade rules.

The render path runs a small allowlist sanitiser before the CSS reaches the visitor’s browser:

ConstructWhat happens
Backslash escape sequences (\)The entire custom CSS block is rejected and the page renders with the default theme only. Avoid Unicode escapes (\\E901), CSS character escapes (\\"), and any other \ use.
@import url(...)The whole @import line is stripped.
url(...) callsThe token url( is rewritten to blocked(, breaking any rule that relied on it. This means external images, @font-face src: url(...), gradient image data URIs, and SVG masks all stop working.
expression(...)Rewritten to blocked(. Legacy IE-only construct; nothing of yours should rely on it.
javascript: URI prefixRewritten to blocked:.

What this means in practice: you can change colours, sizes, spacing, fonts (using fonts that are already on the visitor’s system or that the page already loads), borders, shadows, animations, and pseudo-elements. You cannot load images, custom fonts, or any external resource.

The default theme exposes its colour palette as CSS custom properties on :root. The cleanest way to brand your status page is to set these once at the top of your custom CSS:

:root {
--sp-bg: #fef3e2; /* page background */
--sp-surface: #ffffff; /* card/component background */
--sp-text: #3d2810; /* primary text */
--sp-text-secondary: #6b5343; /* meta text under titles */
--sp-text-muted: #94816d; /* timestamps, separators */
--sp-border: #ead7c1; /* card borders */
--sp-up: #10b981; /* operational green */
--sp-up-light: #d1fae5; /* up-banner background */
--sp-down: #ef4444; /* outage red */
--sp-down-light: #fee2e2; /* down-banner background */
--sp-degraded: #f59e0b; /* degraded amber */
--sp-degraded-light: #fef3c7; /* degraded-banner background */
--sp-unknown: #94a3b8; /* unknown grey */
--sp-accent: #F19030; /* accent colour (footer link, brand chrome) */
--sp-radius: 12px; /* card corner radius */
--sp-radius-sm: 8px; /* small element corner radius */
}

The default theme also has a built-in dark mode that activates on prefers-color-scheme: dark. To customise dark mode, target the same variables inside that media query:

@media (prefers-color-scheme: dark) {
:root {
--sp-bg: #1a0f06;
--sp-surface: #2a1f15;
--sp-text: #fef3e2;
--sp-border: #4a3826;
}
}

Beyond the variables, the page uses a stable sp-* class hierarchy you can target directly:

SelectorWhat it is
.sp-containerThe outer wrapper. Default max-width: 800px, centred. Override here to widen or narrow the page.
.sp-header, .sp-header h1, .sp-header-descPage title + description region at the top.
.sp-bannerThe big overall-status banner. Variants: .sp-banner-up, .sp-banner-degraded, .sp-banner-down, .sp-banner-unknown.
.sp-sectionA group section (e.g. “API”, “Web App”).
.sp-section-titleThe group heading text.
.sp-componentOne monitor row inside a group.
.sp-component-header, .sp-component-name, .sp-component-statusThe row’s flex layout: name on the left, status on the right.
.sp-dotThe status pill before each monitor’s status text. Variants: .sp-dot-up, .sp-dot-down, .sp-dot-degraded, .sp-dot-unknown.
.sp-uptime-infoThe “Uptime: 99.97% (last 30d)” line under each monitor.
.sp-latency-infoThe latency sparkline data, when show_latency is enabled.
.sp-incidents-section, .sp-incidents-titlePast-incidents container.
.sp-incident, .sp-incident-header, .sp-incident-name, .sp-incident-date, .sp-incident-statusIndividual incident cards in the active and past sections. Severity variants: .sp-incident-critical, .sp-incident-warning.
.sp-footer, .sp-footer aThe legal footer at the bottom. The text content is fixed for compliance, but you can restyle it.

Brand-coloured page using your existing palette. Drops in a warm light theme with your accent colour as the link/badge highlight.

:root {
--sp-bg: #fef3e2;
--sp-surface: #ffffff;
--sp-text: #3d2810;
--sp-accent: #F19030;
--sp-border: #ead7c1;
}
.sp-header h1 {
font-weight: 600;
letter-spacing: -0.01em;
}
.sp-banner {
border-radius: 16px;
font-weight: 600;
}

Tighten the layout for an executive dashboard view. Wider container, smaller monitor rows.

.sp-container {
max-width: 1100px;
padding: 1rem 2rem;
}
.sp-component {
padding: 0.5rem 0.875rem;
}
.sp-component-name {
font-size: 0.875rem;
}

Use a system font that is already universally available. No external font-loading; just CSS variable swap.

body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}
.sp-section-title {
text-transform: uppercase;
letter-spacing: 0.06em;
font-size: 0.75rem;
}

Borrow the system status colour from operational, not red, for “Outage”. Useful for an internal-only page where you do not want red flagging anything. (Niche; included to show variant overrides.)

.sp-banner-down {
background: var(--sp-degraded-light);
color: var(--sp-degraded);
}
.sp-dot-down {
background: var(--sp-degraded);
}
  • No external resources. No web fonts hosted on Google Fonts, no images on a CDN, no SVG sprites loaded over url(). The sanitiser breaks every url(...) reference.
  • No script. It is a CSS-only field.
  • No structural changes. You cannot add nodes to the DOM, only restyle existing ones. If a structural change matters to your team, raise it in the console feedback form so we can scope it as a feature rather than a workaround.
  • No overriding the legal footer. You can restyle it, but we keep its text content for compliance; rules that try to display: none or content: '' it are honoured by the browser, but doing so puts your deployment outside the licence terms.

The Custom CSS field in the page editor is a plain textarea, no syntax highlighting, no preview. To iterate, you save and reload the rendered public URL.

Because every status page is public to anyone who knows its URL, the safe pattern is to keep a staging page on an unguessable slug while you iterate, then copy the working CSS to your production page once it looks right:

  1. Create a second status page in the same org with a slug like staging-7c4f (something not enumerable). Set Enabled to true and recreate the same group and monitor layout.
  2. Paste your CSS into the staging page’s Custom CSS field and save. The rendered output is live at /{org-slug}/status/staging-7c4f. Refresh the page after each save to see your edits.
  3. Toggle your browser between light and dark colour schemes (in Chromium DevTools, Rendering → Emulate CSS media feature prefers-color-scheme) to confirm both modes look right.
  4. Once you are happy, copy the CSS into your production page’s Custom CSS field and save.
  5. Either delete the staging page or set Enabled to false; the staging URL then returns 404.

A single org can run multiple status pages. Common patterns:

  • Per audience. A “public.example.com” page for end-users, a “partners.example.com” page for B2B integrations with more detail.
  • Per region. “EU status”, “US status”, link the relevant regional monitors only.
  • Per product line. “Checkout status”, “Reporting status”, different audiences, different monitor sets.

Each page is independently configured (slug, layout, custom CSS, enabled flag). An incident can be linked to any subset of pages, you publish customer-facing communication on the relevant audiences only.

Maintenance windows (feature page) automatically suppress alert pages and render a “Maintenance” badge on the public status page. No incident creation needed, operators schedule the window in advance, the badge appears on the start time and clears on the end time. Banner-level and per-monitor display both honour the window.

  • Test the slug before publishing. Create the page with enabled: false, share the URL with a teammate, then flip the flag once you’re satisfied with the layout.
  • Keep groups stable. Renaming a group is fine; deleting one and recreating it under a different name breaks visitor muscle memory and any external links pointing at section anchors.
  • Don’t put internal infrastructure on a public page. Database servers, message queues, Kubernetes nodes, these add noise without value to customers. The right audience for those is your on-call team via alerts, not a public page.
  • Resolve incidents promptly. A status page with a four-hour-old “still investigating” update reads worse than one with a clean resolution and a postmortem link.
  • Use display_name aggressively. Monitor IDs that make sense internally (e.g., checkout-prod-us-east-1) confuse customers. The display_name override lets you ship a clean public face without renaming the underlying monitor.