---
title: "KPI report template – Display.dev"
description: "A KPI one-pager in self-contained HTML – four numbers, target vs actual, a status pill, and one line of why each moved. Publish it to a URL in one click, no account."
---

# KPI report template

A KPI one-pager in self-contained HTML – four numbers, target vs actual, a status pill, and one line of why each moved. Publish it to a URL in one click, no account.

- Format: HTML
- Detail page: https://display.dev/templates/kpi-report
- Raw template file: https://display.dev/template-sources/kpi-report.html
- One-click anonymous publish (no account): POST the file to https://api.display.dev/v1/public/artifacts as multipart/form-data (`file` field)

## Agent prompt

Build a KPI one-pager for this period on display.dev. Fetch https://display.dev/template-sources/kpi-report.html as the starting point – four KPI cards, each with value, target, an on-track/watch status, and one "why it moved" line. Replace the sample numbers with the real metrics and write the why-lines from actual causes, not restatements of the number. Keep the file self-contained (inline CSS, no external requests).

Publish it with the display.dev MCP publish tool if connected. Otherwise POST the file to https://api.display.dev/v1/public/artifacts as multipart/form-data (`file` field, optional `name`) – no account needed. You'll get back `previewUrl` (the link to share) and `claimUrl` (one-shot link to take ownership). Reply with both.

## What this template is for

The monthly review page that answers the follow-up question before it's
asked. Each of the four cards pairs the number with its target, an
on-track or watch status, and one sentence on *why* it moved – the
sentence that separates a report from a screenshot of a chart.

Four numbers is a constraint, not a limitation: if everything is a KPI,
nothing is.

## How teams use it

- **A monthly business review, assembled by an agent.** The numbers come
  from the warehouse; the why-lines come from the month's actual events –
  the agent drafts both, the owner edits the narrative.
- **Gated to the org.** Revenue and retention belong behind your
  company's Google or Microsoft sign-in. Publish once; the same URL
  serves every month's current version, with history intact.
- **A board-update building block.** Four cards with honest statuses
  travel well into a board deck – or just send the link.

## Template source

````html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>KPI one-pager – June 2026</title>
<style>
  :root {
    color-scheme: light dark;
    --bg: oklch(0.99 0.004 85);
    --card: oklch(1 0 0);
    --fg: oklch(0.16 0.006 85);
    --muted: oklch(0.5 0.008 85);
    --line: oklch(0.92 0.006 85);
    --accent: oklch(0.48 0.18 145);
    --warn: oklch(0.68 0.16 50);
  }
  @media (prefers-color-scheme: dark) {
    :root {
      --bg: oklch(0.15 0.005 85);
      --card: oklch(0.19 0.006 85);
      --fg: oklch(0.97 0.004 85);
      --muted: oklch(0.65 0.008 85);
      --line: oklch(0.3 0.006 85);
      --accent: oklch(0.68 0.18 145);
      --warn: oklch(0.75 0.15 50);
    }
  }
  * { box-sizing: border-box; }
  body {
    margin: 0; background: var(--bg); color: var(--fg);
    font-family: ui-sans-serif, system-ui, sans-serif;
    line-height: 1.5; padding: clamp(1.5rem, 4vw, 3rem);
  }
  .wrap { max-width: 840px; margin: 0 auto; }
  h1 { font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 700; letter-spacing: -0.02em; margin: 0; }
  .meta { color: var(--muted); font-size: 0.9375rem; margin: 0.25rem 0 1.5rem; }
  .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0.75rem; }
  .kpi {
    background: var(--card); border: 1px solid var(--line);
    border-radius: 10px; padding: 1.125rem 1.25rem;
  }
  .kpi .label { font-size: 0.75rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
  .kpi .value { font-size: 1.875rem; font-weight: 700; letter-spacing: -0.02em; margin: 0.25rem 0 0.125rem; }
  .kpi .target { font-size: 0.8125rem; color: var(--muted); }
  .kpi .status { display: inline-block; font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin-top: 0.5rem; padding: 0.125rem 0.5rem; border-radius: 999px; border: 1px solid var(--line); }
  .kpi .status.on { color: var(--accent); border-color: var(--accent); }
  .kpi .status.watch { color: var(--warn); border-color: var(--warn); }
  .kpi p { margin: 0.625rem 0 0; font-size: 0.875rem; color: var(--muted); line-height: 1.55; }
  .kpi p strong { color: var(--fg); font-weight: 600; }
  footer { color: var(--muted); font-size: 0.8125rem; margin-top: 1.5rem; }
</style>
</head>
<body>
<div class="wrap">
  <h1>KPI one-pager – June 2026</h1>
  <p class="meta">Monthly business review · four numbers, one line of context each · owner: Sara L.</p>

  <div class="grid">
    <div class="kpi">
      <div class="label">Monthly recurring revenue</div>
      <div class="value">€418k</div>
      <div class="target">Target €425k · +6.1% MoM</div>
      <span class="status on">On track</span>
      <p><strong>Why it moved:</strong> 14 upgrades from the June pricing
      change; churn flat. Gap to target closes if July upgrades hold rate.</p>
    </div>
    <div class="kpi">
      <div class="label">Net revenue retention</div>
      <div class="value">104%</div>
      <div class="target">Target 108% · −1 pt MoM</div>
      <span class="status watch">Watch</span>
      <p><strong>Why it moved:</strong> two mid-market downgrades at seat
      review. Churn interviews point at the seat-count step – fix scoped
      for v2.14.</p>
    </div>
    <div class="kpi">
      <div class="label">Weekly active teams</div>
      <div class="value">1,932</div>
      <div class="target">Target 1,900 · +9% MoM</div>
      <span class="status on">On track</span>
      <p><strong>Why it moved:</strong> onboarding rework lifted week-one
      activation from 34% to 41%; the cohort is carrying WAT with it.</p>
    </div>
    <div class="kpi">
      <div class="label">Gross margin</div>
      <div class="value">81%</div>
      <div class="target">Target 80% · flat MoM</div>
      <span class="status on">On track</span>
      <p><strong>Why it moved:</strong> stable. Compute renegotiation lands
      in August; expect +1–2 pts from September.</p>
    </div>
  </div>

  <footer>Definitions in the metrics handbook · numbers are sample data, replace with your own.</footer>
</div>
</body>
</html>
````
