What is forecast accuracy, and how do you measure it in Metabase?
Forecast accuracy measures how close your forecast came to what actually closed. It's the metric that tells you whether to trust the number leadership commits to the board — and the one most teams can't compute because they never saved the forecast. Measure it in Metabase from CRM and revenue-intelligence data synced into a database (Salesforce, HubSpot, Gong, Salesloft/Clari).
How is forecast accuracy defined?
There are a few common formulations — pick one and hold it:
- Accuracy = 1 − |actual − forecast| ÷ forecast — the symmetric, headline number. 100% means a perfect call.
- Variance = actual − forecast — the signed miss, which reveals direction (over vs. under).
- Attainment = actual ÷ forecast — a ratio some teams prefer for quota-style reporting.
Report accuracy for the headline and bias (signed variance) for diagnosis — a team that's accurate on average but always over-forecasts has a real problem the accuracy number hides.
Why you need forecast snapshots
This is the part teams miss. A live CRM only tells you the pipeline right now. To measure accuracy you need the forecast as it stood at the commitment point — start of quarter, or each week. Capture a periodic snapshot of forecast amount (and stage/category) so you can compare it to what actually closed.
- Start-of-period snapshot answers "how good was the initial call?"
- Weekly snapshots answer "how does the forecast converge as the quarter progresses?"
What data does forecast accuracy need?
- A forecast snapshot table with period, snapshot date, and forecast amount (ideally by category: commit, best case, pipeline).
- Actual closed-won amounts per period from the deals table.
- A consistent period definition (fiscal quarter, month) across both.
- Segmentation columns: team, region, and forecast category.
SQL patterns
-- Forecast accuracy by quarter: forecast vs. actual closed-won
SELECT
f.period,
f.forecast_amount,
a.actual_amount,
ROUND(
100.0 * (1 - ABS(a.actual_amount - f.forecast_amount)
/ NULLIF(f.forecast_amount, 0)),
1
) AS accuracy_pct
FROM modeled_forecast_snapshots f
JOIN (
SELECT period, SUM(amount) AS actual_amount
FROM modeled_deals
WHERE is_won
GROUP BY period
) a ON a.period = f.period
WHERE f.snapshot_type = 'start_of_period'
ORDER BY f.period;-- Forecast bias: are we consistently over- or under-forecasting?
SELECT
f.period,
f.forecast_amount,
a.actual_amount,
a.actual_amount - f.forecast_amount AS variance,
CASE
WHEN a.actual_amount >= f.forecast_amount THEN 'under-forecast'
ELSE 'over-forecast'
END AS direction
FROM modeled_forecast_snapshots f
JOIN (
SELECT period, SUM(amount) AS actual_amount
FROM modeled_deals
WHERE is_won
GROUP BY period
) a ON a.period = f.period
ORDER BY f.period;Pitfalls
Where this metric applies
- Salesforce + Metabase — forecast categories and opportunity amounts
- HubSpot + Metabase — forecast and deal amounts
- Gong + Metabase — deal and forecast signals from conversations
- Salesloft/Clari + Metabase — revenue-intelligence forecast data