Build a roll-your-own status.yourdomain page

Data-driven status dashboard: ingest health, recent incidents, 7d MTTR. CORS-open + iframe-able. More honest and cheaper than Statuspage.io.

Published

difficulty advanced · time to value 20 minutes · tools used 4

Just say this

Compose a public status dashboard: current ingest health (logs / analytics / deploys), recent incidents (cases in the last 24h with users_affected ≥ 10), and MTTR for the last 7 days. Publish as a CORS-open dashboard I can iframe on status.mydomain.com.

Why this matters

Most status pages are theater. The vendor SaaS (Statuspage.io, BetterUptime, etc.) gives you a green-bar template that someone on call has to manually flip to yellow when an incident hits. They almost never do, because:

  1. Mid-incident is the worst time to also update a status page
  2. The status page becomes a lie (“all systems operational” while customers are getting 500s)
  3. Engineers stop trusting it; customers stop trusting it; it’s purely decorative

The honest version: a data-driven status page that reads directly from your real metrics. No human flips a switch — the page shows actual ingest rates, actual incident counts, actual MTTR. When it lies, you have a real bug to fix; when it shows yellow, customers can see why.

Agentry’s published dashboards are CORS-open and embed-friendly. The whole thing is three queries and an iframe.

What you get

  • A public, embeddable status page with three sections:
    • Now: ingest health (events received in last 5 min vs baseline)
    • Recent incidents: open cases in last 24h with ≥ 10 users affected
    • MTTR (7d): median time from case.created to case.resolved
  • A URL pattern you can iframe on status.yourdomain.com
  • No vendor SaaS, no monthly fee, no green-by-default lie

Walk through it

You

Compose a public status dashboard: current ingest health (logs / analytics / deploys), recent incidents (cases in last 24h with users_affected ≥ 10), and MTTR for the last 7 days. Publish as a CORS-open dashboard I can iframe on status.mydomain.com.

Agent

Three publishable queries. Let me build and publish each, then hand back the iframe snippets.

agentry_publish_query {
  recipe_id: "raw_hogql",
  description: "Status: ingest health (5min vs baseline)",
  params: {
    query: "
      with recent as (
        select count() as n_5min
        from events
        where timestamp > now() - interval 5 minute
      ),
      baseline as (
        select count() / (7 * 24 * 12) as baseline_per_5min
        from events
        where timestamp > now() - interval 7 day
      )
      select
        r.n_5min,
        b.baseline_per_5min,
        r.n_5min / b.baseline_per_5min as ratio,
        case
          when r.n_5min / b.baseline_per_5min between 0.5 and 2.0 then 'operational'
          when r.n_5min / b.baseline_per_5min < 0.5 then 'degraded'
          else 'elevated_volume'
        end as status
      from recent r cross join baseline b
    "
  }
}
{ "publication_id": "pub_status_ingest", "public_url": "https://agentry.sh/q/pub_status_ingest?key=agp_…" }
agentry_publish_query {
  recipe_id: "raw_hogql",
  description: "Status: recent incidents (24h, ≥10 users)",
  params: {
    query: "
      select
        case_id, fingerprint, error_type, message, first_seen_at,
        users_affected, events_count, status
      from cases
      where first_seen_at > now() - interval 24 hour
        and users_affected >= 10
        and status in ('open', 'investigating')
      order by users_affected desc
      limit 10
    "
  }
}
{ "publication_id": "pub_status_inc", "public_url": "https://agentry.sh/q/pub_status_inc?key=agp_…" }
agentry_publish_query {
  recipe_id: "raw_hogql",
  description: "Status: MTTR (7d)",
  params: {
    query: "
      select
        quantile(0.5)(dateDiff('minute', first_seen_at, resolved_at)) as mttr_median,
        quantile(0.9)(dateDiff('minute', first_seen_at, resolved_at)) as mttr_p90,
        count() as resolved_count
      from cases
      where status = 'resolved'
        and resolved_at > now() - interval 7 day
    "
  }
}
{ "publication_id": "pub_status_mttr", "public_url": "https://agentry.sh/q/pub_status_mttr?key=agp_…" }
Agent

Three queries published. Here’s the iframe snippet you can drop on status.yourdomain.com:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>System status — yourdomain</title>
  <style>
    body { font-family: ui-sans-serif, system-ui, sans-serif; max-width: 720px; margin: 2rem auto; padding: 0 1rem; color: #1c1c1c; }
    iframe { width: 100%; border: 1px solid #e5e5e5; border-radius: 8px; }
    h1, h2 { letter-spacing: -0.01em; }
    .grid-3 { display: grid; gap: 0.75rem; grid-template-columns: repeat(3, 1fr); margin-bottom: 1.5rem; }
    .status-good { color: #15803d; } .status-bad { color: #b91c1c; }
  </style>
</head>
<body>
  <h1>System status</h1>

  <h2>Right now</h2>
  <iframe src="https://agentry.sh/q/pub_status_ingest?key=agp_xxx" height="120" title="Ingest health"></iframe>

  <h2>Active incidents (24h)</h2>
  <iframe src="https://agentry.sh/q/pub_status_inc?key=agp_xxx" height="300" title="Incidents"></iframe>

  <h2>7-day MTTR</h2>
  <iframe src="https://agentry.sh/q/pub_status_mttr?key=agp_xxx" height="120" title="MTTR"></iframe>

  <p style="color: #6b7280; font-size: 0.85rem;">
    Driven by real production telemetry, refreshed every minute.
    No human flips this dashboard between green and red — if it shows yellow,
    something is actually misbehaving.
  </p>
</body>
</html>

One detail: by default the queries are evaluated on each page load. If you have very high traffic on status.yourdomain.com, add ?cache=60 to each iframe URL — Agentry will cache the result for 60s and bypass re-evaluation per visit.

The output

Published status page components

  pub_status_ingest    "Now" — events in last 5min vs 7d baseline
  pub_status_inc       "Incidents" — 24h cases with ≥10 users
  pub_status_mttr      "MTTR" — median + p90 over 7d

Embed-ready iframes (CORS-open, agp_ keyed, ratelimited 60 req/min):
  https://agentry.sh/q/pub_status_ingest?key=agp_xxx
  https://agentry.sh/q/pub_status_inc?key=agp_xxx
  https://agentry.sh/q/pub_status_mttr?key=agp_xxx

Sample rendered output:

  System status — yourdomain
  ─────────────────────────────────────
  Right now
    Events/5min:    12,400 (1.04× baseline)    ✓ operational

  Active incidents (24h)
    [none]

  7-day MTTR
    median: 42 minutes
    p90:   2h 14m
    resolved this week: 14

  Driven by real telemetry, refreshed every minute.

Setting it up

1. Subdomain. Point status.yourdomain.com to a static host (Cloudflare Pages, Vercel, Netlify all work). The page is one HTML file with the iframes above.

2. Caching. Default behavior re-runs the queries on each load. Add ?cache=60 to each iframe src so the queries cache for 60s — protects you from someone hitting the page 1000 times during an incident.

3. CSP-safe. If you have a strict CSP on the parent page, you’ll need to add https://agentry.sh to frame-src. Server-side fetch is the alternative — pull JSON and render server-side:

// Astro / Next / your framework
const res = await fetch(
  `https://agentry.sh/q/pub_status_ingest?key=${AGP_KEY}&format=json`,
  { headers: { "User-Agent": "status-page/1.0" } }
);
const { rows } = await res.json();
const status = rows[0].status;  // 'operational' | 'degraded' | ...

4. Branding. The iframe content is plain HTML — Agentry serves it with neutral styling. Drop your own CSS into the parent page and style the iframes with border: 0; background: transparent;.

5. Honest copy. Resist the urge to add manual “we’re investigating” banners. The whole point of this page is that it never lies, and a human-curated banner re-introduces the failure mode of vendor status pages.

Variations

  • “Add a 4th component: per-service breakdown. ingest/auth/checkout/api as separate rows.”
  • “Make the incident list show only the agent_summary (not the raw error message) — friendlier for customers.”
  • “Per-region status: filter ingest health by properties.region so EU/US/APAC are separately displayed.”
  • “Add a ‘historical uptime %’ computed as (1 - hours_with_active_incidents / 720) over the last 30 days.”
  • “Embed in a Notion page using their /embed block instead of a standalone subdomain.”

Try this recipe in your own agent.

Paste the prompt above into your agent. It'll set up Agentry against your data, then run the recipe and show you the real output.

Install https://agentry.sh/agentry.md and set it up