How to build incident.io dashboards in Metabase
incident.io is an incident management platform for declaring, running, and learning from incidents — with on-call, status pages, and post-incident workflows built in. Metabase is where you turn those operational signals into shared, trustworthy dashboards. This guide covers two complementary paths: a lightweight MCP + CLI route that pulls live data with the incident.io MCP server and loads a CSV into Metabase with the Metabase CLI, and a durable pipeline route that syncs incident.io rollups into a database so you can build dashboards anyone can read.
How do you connect incident.io to Metabase?
Most teams combine both routes: use MCP and CLI uploads for a fast first pass, then move recurring reliability reporting to a warehouse-backed model.
Live data in, quick analysis out
Pair the incident.io MCP server with the Metabase CLI. Use MCP for live lookups, write a scoped result to CSV, then load it into Metabase as a ready-to-query table and model.
- Quick lookups such as "show me incident health with mtta and mttr"
- Loading a incident.io export into Metabase in seconds
- Spot-checks and one-off analyses without a warehouse
- Great for exploration, not governed reliability reporting
- Use read-only/scoped credentials wherever the MCP server supports them
- CSV uploads are snapshots — refresh or move to the pipeline for history
Durable dashboards with history
Sync incident.io rollups and metadata into a database or warehouse with a connector, custom pipeline, or API, then point Metabase at it.
- incident.io reliability dashboards leaders depend on
- Joining incident.io data with deploys, issues, support, or cost data
- Long-run trends for incident health with mtta and mttr and incident volume by severity and type
- You own the refresh schedule and the rollup grain
- Sync aggregates and entities — not the raw event firehose
- Metric definitions must be consistent across services and teams
What can you analyze from incident.io data in Metabase?
- Incident health with MTTA and MTTR — built from incidents and the related follow-ups, escalations, incident roles data your sync exposes.
- Incident volume by severity and type — built from incidents and the related follow-ups, escalations, incident roles data your sync exposes.
- Follow-up completion and aging — built from incidents and the related follow-ups, escalations, incident roles data your sync exposes.
- On-call and escalation load — built from incidents and the related follow-ups, escalations, incident roles data your sync exposes.
- Status page communication cadence — built from incidents and the related follow-ups, escalations, incident roles data your sync exposes.
Which incident.io dashboards should you build in Metabase?
Incident health
Volume, acknowledgment, and recovery at a glance.
- Incidents per week by severity (stacked bar)
- Median time to acknowledge (line)
- Median time to resolve (line)
- Open incidents right now (number)
Alert quality
Whether alerts are signal or noise.
- Alerts fired per week (line)
- Alert-to-incident conversion rate (number + trend)
- Noisiest services or monitors (table)
- Auto-resolved alerts share (number)
On-call load
Whether the pager is sustainable for the humans.
- Pages per on-call shift (bar)
- Off-hours pages per week (line)
- Escalations per week (bar)
- Pages by service (table)
Service reliability
Which services drive incident load over time.
- Incidents by service, trailing 90 days (bar)
- Repeat incidents on the same service (table)
- MTTR by service (bar)
- Postmortem completion rate (number)
How do you use the incident.io MCP server with the Metabase CLI?
Pair the incident.io MCP server with the Metabase CLI for fast, hands-on analysis. MCP is useful for scoped lookups and summarized exports; the Metabase CLI's upload command loads CSV data into Metabase and creates a ready-to-query table and model.
Example workflow
- Ask the MCP server for recent incidents with acknowledge and resolve timestamps.
- Export the result as CSV, keeping stable IDs, services, environments, severities, and timestamps.
- Run
mb upload csvto load it into Metabase as a table and model, then build questions and dashboards on top.
Be honest about the limits
- MCP lookups are excellent for exploration, not scheduled reporting.
- A CSV upload is a snapshot; refresh it with
mb upload replaceor move to the pipeline for real history. - Acknowledge and resolve timestamps are required for true MTTA and MTTR.
mb upload csvneeds an uploads database configured under Admin → Settings → Uploads.
How do you set up incident.io MCP and the Metabase CLI?
incident.io MCP serverofficial
- Transport
- Hosted remote MCP via Streamable HTTP
- Auth
- OAuth or an API key (Bearer)
- Best for
- Live scoped lookup and export
Metabase CLIofficial
- Install
npm install -g @metabase/cli- Auth
mb auth login- Load data
mb upload csv --file data.csv- Requires
- An uploads database (Admin → Settings → Uploads)
{
"mcpServers": {
"incident-io": {
"url": "https://mcp.incident.io/mcp"
}
}
}Public Beta on Team, Pro, and Enterprise plans; enable it under Settings → MCP. The incident_stats, alert_stats, and escalation_stats tools return aggregates directly — handy for analytics exports.
# Install the Metabase CLI
npm install -g @metabase/cli
# Log in (opens your browser; requires Metabase v62+)
mb auth login --url https://your-metabase.example.com
# Load a incidents export — creates a table AND a model
mb upload csv --file incident-io-incidents.csv --collection root
# Refresh that same table later from a new export
mb upload replace <table-id> --file incident-io-incidents.csvCan you generate a incident.io dashboard with AI?
Yes. Use the prompt below with any assistant that can run the incident.io MCP server and the Metabase CLI. It works end to end: if incident.io tables already exist in Metabase it analyzes those; otherwise it pulls scoped, summarized data over MCP, loads it with mb upload csv, then builds the dashboard and caveats any metric that needs missing history.
Create a polished Metabase dashboard for incident.io incident management analytics.
Work end to end: get the data into Metabase if it isn't there yet, then build.
Goal: Help engineering and operations leaders understand incident volume, MTTA, MTTR, alert noise, on-call load, and service reliability from incident.io data.
Step 1 — Find or load the data:
- First, check what already exists in Metabase (search for incident-io tables and
models). If durable incident.io data is already present — synced from a warehouse
or uploaded earlier — use it and skip to Step 2.
- If nothing is there, pull a scoped, summarized export with the incident.io MCP server:
incidents, plus follow-ups, escalations, incident roles.
Prefer aggregated or rollup views over raw events. Write each result to a CSV,
then load it with the Metabase CLI — run "mb upload csv --file <export>.csv" so
each upload creates a table and a ready-to-query model. Use "mb upload replace
<table-id> --file <export>.csv" to refresh an existing table instead of creating
duplicates.
Step 2 — Inspect before querying:
Do not assume exact table or column names. Inspect available fields, services,
environments, timestamps, and whether rollups or history exist before creating
duration or trend cards.
Important:
- Build on whatever data is present; don't claim Metabase connects natively to
incident.io — it reads a database or CLI-uploaded tables.
- Never try to load the raw event firehose into Metabase; use rollups, entity
tables, and incident- or group-grain data.
- Only compute durations (MTTA, MTTR, time-to-resolve) when the required
timestamps exist.
- Exclude test, staging, or muted objects from headline reliability cards, and
segment by environment where the field exists.
- A single CSV is a point-in-time snapshot: only build trend cards if there is a
usable date column or multiple periods have been uploaded.
Dashboard title: incident.io Incident Management Overview
Sections:
1. Executive summary: Open incidents; Incidents last 30 days; Median MTTA;
Median MTTR; High-urgency share.
2. Volume: Incidents by week and severity; incidents by service and team.
3. Response: MTTA and MTTR trends; incidents breaching response targets.
4. Alert quality: Alerts by week; alert-to-incident conversion; noisiest services.
5. On-call load: Pages per shift; off-hours pages; escalation rate.
Filters: Date range, Service, Environment, Severity, Team, Status.
Output: Build the dashboard if you have permission; otherwise provide the exact
questions, SQL, model definitions, and layout. Include caveats for any metric
that cannot be calculated from the available data.How do you sync incident.io data into a database or warehouse?
For dashboards that need history and reliability, land incident.io rollups and metadata in a database first, then connect Metabase to that database.
Connector options
- Managed ETL — use a connector when one covers the objects you need.
- Custom pipeline — use the incident.io API for control over rollup grain, fields, and refresh cadence.
- MCP + CSV — use this for quick exploration and one-off slices.
Sync incidents, follow-ups, and metadata with the Airbyte incident.io source or a dlt pipeline against the incident.io API — both authenticate with an API key.
Notes
- Decide the rollup grain first (hourly or daily per service/environment) — it drives warehouse cost and every trend card.
- Land raw entity tables first, then build clean Metabase models on top.
- Normalize service, team, severity, created, acknowledged, and resolved-timestamp fields.
How should you model incident.io data in Metabase?
Core tables
| Table | Grain | Key columns |
|---|---|---|
incidents | one row per incident | id, severity, incident_type, status, service_name, created_at, acknowledged_at, resolved_at |
incidentio_followups | one row per follow-up action | id, incident_id, status, assignee_id, created_at, completed_at |
incidentio_escalations | one row per escalation | id, incident_id, escalation_path, created_at, acknowledged_at |
Modeling advice
- Build a clean
incidentsmodel with common columns across tools, so multi-source dashboards don't fork definitions. - Separate entity tables (services, monitors, policies) from time-series rollups and event-grain tables.
- Exclude test, staging, and muted objects from headline reliability metrics; keep environment as an explicit column.
- Use stable IDs for service, team, and incident joins; display names change.
Which incident.io metrics should you track in Metabase?
| Metric | Definition | Notes |
|---|---|---|
| Incident count | Qualifying incidents per period, segmented by severity. | Watch the trend by service, not one number. |
| Mean time to acknowledge | Created to first acknowledge, as a median. | A paging-health metric — separate from MTTR. |
| MTTR | Median time from incident start to resolution. | Segment by severity; exclude open incidents. |
| Alert noise rate | Alerts that never became incidents divided by all alerts. | High noise trains responders to ignore pages. |
| SLO compliance | Periods meeting the SLO target divided by all periods. | Report against explicit, published targets. |
What SQL powers incident.io dashboards in Metabase?
These assume a cleaned analytical model in a warehouse (PostgreSQL dialect). Adjust table and column names to match your pipeline.
The core incident-health trend.
SELECT
date_trunc('month', created_at) AS month,
COUNT(*) AS incidents,
COUNT(*) FILTER (WHERE resolved_at IS NOT NULL) AS resolved_incidents,
percentile_cont(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (acknowledged_at - created_at)) / 60
) FILTER (WHERE acknowledged_at IS NOT NULL) AS median_ack_minutes,
percentile_cont(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (resolved_at - created_at)) / 60
) FILTER (WHERE resolved_at IS NOT NULL) AS median_resolve_minutes
FROM incidents
GROUP BY 1
ORDER BY 1;Alerts that never became incidents.
SELECT
service_name,
COUNT(*) AS alerts,
COUNT(*) FILTER (WHERE became_incident) AS incidents,
ROUND(
100.0 * COUNT(*) FILTER (WHERE NOT became_incident)
/ NULLIF(COUNT(*), 0), 1
) AS noise_rate
FROM alerts
WHERE fired_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY service_name
ORDER BY noise_rate DESC;Where incident load concentrates, trailing 90 days.
SELECT
service_name,
severity,
COUNT(*) AS incidents,
percentile_cont(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (resolved_at - created_at)) / 3600
) AS median_resolve_hours
FROM incidents
WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'
AND resolved_at IS NOT NULL
GROUP BY service_name, severity
ORDER BY incidents DESC;