Pipeline Coverage
Weighted pipeline stacked against the gap to quota, with a coverage ratio and the probability of hitting plan.
Q2 2026 · Pipeline Coverage
2.9×
$4.1M pipeline · $1.4M gap
Quota has a 44% chance of hitting plan by quarter end.
| Stage | Value | Win prob |
|---|---|---|
| Prospect | $1.6M | 10% |
| Qualify | $920k | 22% |
| Proposal | $780k | 45% |
| Negotiation | $520k | 65% |
| Verbal | $280k | 88% |
Salesforce · updated hourly
Demo data is illustrative. Replace with your own typed data prop.
How it computes
Probability-weighted pipeline vs the gap to quota, with a Gaussian estimate of P(bookings ≥ gap).
gap = max(0, quota − closedWon); weighted = Σ value·winProb; σ = √(Σ value²·p(1−p)); P = 1 − Φ((gap − weighted)/σ)Assumptions
- Stage win-probabilities are independent (Bernoulli per opportunity).
- The normal approximation holds across the set of opportunities.
- quota − closedWon is the true remaining gap.
Honest about
- Coverage is reported as ∞ when the gap is already closed, rather than a misleading finite ratio.
- σ assumes independence — real deal correlations are not modeled, so a concentrated pipeline is riskier than the interval implies.
- The "healthy" coverage multiple (default 3×) is an industry reference line, not a statistical threshold.
Use it with your data
Data contract
Passed via the data prop — an object: validated at runtime, so a bad shape degrades to the error state rather than crashing.
| Field | Type | Required |
|---|---|---|
| quota | number | yes |
| closedWon | number | yes |
| stages | array | yes |
Static props
import { SalesPipelineCoverage } from "@/components/blocks/sales-pipeline-coverage/sales-pipeline-coverage";
<SalesPipelineCoverage data={myData} />Client fetch (SWR)
const { data, isLoading, error } = useSWR("/api/metric", fetcher);
// route isLoading/error through <ChartStates>, then:
<SalesPipelineCoverage data={data} />Server component (RSC)
const data = await fetch(url, {
next: { revalidate: 3600 },
}).then((r) => r.json());
<SalesPipelineCoverage data={data} />Map arbitrary rows
import { mapRows } from "@/lib/sextant/column-map";
const out = mapRows(rows, { /* contractKey: "yourColumn" */ }, dataSchema);
if (out.ok) <SalesPipelineCoverage data={out.data} />;Make it yours
Every customization below is an optional prop — omit them all and you get the defaults shown above. Recolor, reformat, restyle, or drop the card chrome without forking the component.
Recolor or rename a series (pipeline)
<SalesPipelineCoverage
series={{ pipeline: { color: "var(--chart-3)", label: "…" } }}
/>Format numbers (currency / locale)
const eur = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
notation: "compact",
});
<SalesPipelineCoverage valueFormatter={(n) => eur.format(n)} />Replace or hide the narrative
<SalesPipelineCoverage narrative="Your own one-liner." />
// …or hide it entirely:
<SalesPipelineCoverage narrative={false} />Restyle any region
<SalesPipelineCoverage
className="max-w-xl"
classNames={{ body: "bg-muted/20" }}
/>Drop the card chrome (headless plot)
import { SalesPipelineCoveragePlot } from "@/components/blocks/sales-pipeline-coverage/sales-pipeline-coverage";
// Just the chart body — bring your own card/layout:
<SalesPipelineCoveragePlot data={data} config={config} />