dashboard
A dashboard is read in 5 seconds by someone who will not scroll. If a busy reader cannot grasp business status that fast, the design failed — no matter how accurate the numbers are. Your job here is arrangement, framing, and chart choice, producing a checkable artifact:
dashboard.yaml— a tile manifest (each tile: metric, chart, comparison, owner, refresh, decision).- a one-screen layout sketch placing the north-star top-left.
You do not decide which metrics matter (that is kpi-framework) and you do not wire the data source (that is analytics). You take a metric set that already exists and make it readable at a glance.
Run scripts/verify.sh dashboard.yaml before you hand off. It checks shape and discipline — tile count 1-9, exactly one north_star: true, the required keys on every tile, no banned charts — never whether the numbers are correct.
The Decision Test gate
No tile exists until its metric names the action it drives. Ask: what does someone do differently based on this number? If the answer is vague ("good to know", "shows we're growing"), the metric is vanity — cut it or convert it. A tile that changes no decision is decoration.
| Vanity metric (Bad) | Actionable conversion (Good) | Decision it drives |
|---|---|---|
| Total followers | Follower-growth rate WoW | Double down or change content cadence |
| Total page views | Conversion rate by source | Reallocate spend to the converting channel |
| Cumulative signups | Activation rate (signup → key action) | Fix onboarding if activation drops |
| Total revenue (all-time) | MRR + net revenue retention | Whether to hire / extend runway |
| App downloads | 7-day retention | Kill or scale the acquisition channel |
Rule: an always-up counter ("total X") is almost always vanity. Convert it to a rate or ratio that can go down. Why: a number that only ever rises never triggers an action.
Tile budget: 5-9, exactly one north-star
Executive dashboards carry roughly 5 to 9 KPIs. Human working memory caps near ~7 items; more tiles cause analysis paralysis and the screen stops being a glance.
- Exactly one tile flagged
north_star: true. Why: a glance needs a single first read. - 4-8 supporting tiles around it. Total ≤ 9.
When a stakeholder demands 20 metrics, do not cram them — tier:
- Does this metric drive a decision the leadership team makes weekly? → main screen.
- Is it a diagnostic you only check after a main tile turns red? → drill-down view, linked from the parent tile.
- Is it commentary / context that needs prose? → route to reporting, not a tile.
- Is it a projection of a metric forward? → forecasting, not the live screen.
- Does the user want to slice it freely by dimension? → business-intelligence, not a fixed tile.
Framing every tile
The minimum viable tile is not a number. It is a number plus the context that makes it actionable:
value + comparison(target | prior | benchmark) + delta + units + date range
+ RYG status + owner + refresh cadence
Bad → Good:
Bad: Churn: 4.1%
Good: Monthly logo churn — 4.1% ▲0.6pp vs prior month (target ≤3.0%) 🔴
Owner: Head of CS · Refresh: daily · Range: May 2026
Why each field earns its place:
- comparison — a number alone has no "is this good?"; target/prior/benchmark supplies it.
- delta — direction and magnitude of change is the second thing the eye wants.
- units + date range — "4.1%" of what, over what window; ambiguity kills trust.
- RYG status — lets the reader triage in the 5-second glance without reading the number.
- owner — every red tile needs an accountable human, or nothing happens.
- refresh cadence — tells the reader how stale the number can be; a "real-time" label on a weekly metric is a lie.
Chart per metric: pick by shape
Choose the chart from the shape of the question, not from what looks impressive. Full matrix and edge cases in references/chart-selection.md.
| Metric shape | Chart | Why |
|---|---|---|
| Single headline number | Big-number tile + delta | Fastest read; the north-star usually lives here |
| Trend over time | Line | Slope shows direction instantly |
| Category comparison | Sorted horizontal bar | Length is easy to compare; sorting answers "who's worst" |
| Target vs actual | Bullet chart | Compact, comparable; replaces gauges/dials |
| Part-to-whole (≤5 parts) | Stacked bar or treemap | Pie only legible to 3-5 slices |
| Correlation | Scatter | Shows relationship between two measures |
| Distribution | Histogram | Shape of spread, not just average |
Kill-list: no pie beyond 5 categories (sorted bar instead) and no gauge / dial (bullet chart instead) — verify.sh rejects both; no dual-axis, which invents correlations that aren't there; no 3D and no donut-with-center-number gimmicks.
Layout & data-ink
Lay tiles out for the Z / F scan pattern: the eye starts top-left, sweeps right, drops down. Put the north-star top-left; group related KPIs together (acquisition cluster, revenue cluster, health cluster).
Apply the data-ink ratio: if a pixel shows no new information, remove it. Strip heavy borders, drop shadows, gradients, 3D, background textures — they raise cognitive load without adding meaning.
Color is meaning, not decoration. Use a status palette (red/yellow/green) only for status. A rainbow of tile colors with no semantic meaning makes the screen harder, not friendlier.
Before: 9 boxed-and-shadowed tiles, each a different bright color,
3 pie charts, two gauges, no clear starting point.
After: north-star top-left (big number + sparkline);
flat tiles, hairline separators, neutral palette;
RYG reserved for status; bullets replace gauges;
sorted bar replaces the pies.
The artifact: dashboard.yaml
Emit a manifest a BI tool, a web app, or a human can build from. Short schema here; full field reference in references/tile-schema.md.
# dashboard.yaml — one screen, one north-star
title: SaaS Exec Dashboard
date_range: "2026-05"
tiles:
- id: waa
north_star: true
metric: Weekly Active Accounts
chart: big_number # + sparkline trend
value_source: warehouse.fct_active_accounts
units: accounts
comparison: { type: target, value: 1200 }
delta: vs_prior_week
status_logic: "green ≥ target; yellow ≥ 90%; red < 90%"
owner: VP Product
refresh: daily
decision: "If below 90% of target two weeks running, escalate activation work."
- id: nrr
metric: Net Revenue Retention
chart: big_number
comparison: { type: benchmark, value: 110 } # %
units: percent
owner: VP Sales
refresh: monthly
decision: "Below 100% triggers a save/expansion review."
- id: churn
metric: Monthly Logo Churn
chart: line
comparison: { type: target, value: 3.0 }
units: percent
owner: Head of CS
refresh: daily
decision: "Above target investigates cohort + reason codes."
- id: runway
metric: Cash Runway
chart: bullet # actual vs target months
comparison: { type: target, value: 18 }
units: months
owner: CFO
refresh: monthly
decision: "Under 12 months opens fundraise / cost review."
- id: pipeline
metric: New Pipeline by Source
chart: sorted_bar
comparison: { type: prior, value: last_month }
units: currency
owner: Head of Marketing
refresh: weekly
decision: "Shift spend toward the top-converting source."
layout:
north_star: top_left
scan: Z
groups: [growth, revenue, health]
The keys verify.sh requires on every tile: metric, chart, comparison, owner, refresh, decision.
Anti-patterns
| Anti-pattern | Why it fails | Do instead |
|---|---|---|
| 20 tiles on one screen | Past ~7, no one can read it in 5 seconds | Cut to 5-9; tier the rest to a drill-down |
| Vanity metrics (totals, followers) | Never trigger an action | Apply the Decision Test; convert to rates |
| Bare numbers, no comparison | No "is this good?" signal | Add target / prior / benchmark + delta |
| Pie chart with 8 slices | Slices become unreadable | Sorted horizontal bar |
| Gauges and dials | Waste space, resist comparison | Bullet chart |
| Rainbow tile colors | Color reads as meaning when it isn't | Neutral tiles; RYG for status only |
| "Real-time" on everything | False precision; refresh-cost theater | Match refresh to decision cadence |
| It's actually a report | Prose + commentary isn't a glance | Move narrative to reporting |
| No north-star | Reader has no entry point | One north_star: true tile, top-left |
Handoff
Beyond the routes named above: reading out an experiment or variant significance → ab-testing; visual polish, spacing and type scale of the rendered screen → design; pulling or joining the underlying numbers in a sheet → spreadsheet-ops.