Sujata Karan
LAB · SALES ANALYTICS CASE STUDY

Pipeline Health & Forecast Accuracy

Are we going to hit the number this quarter, and can we trust what the reps are telling us? A sales analytics build in SQL, Python and Metabase.

5.4x → 2.3x
Pipeline coverage at quarter start, as quota doubled
7%
Win rate for deals whose close date was pushed three or more times
< 10%
Forecast error of a simple model, in every week of the quarter
20–24%
How far rep forecasts ran high in the last month of the quarter

The problem

Every week a sales leader asks the same two questions: will we hit the number, and how much of what the team is committing can we believe?

The answer usually sits in a CRM that only shows today. Salesforce can tell you what the pipeline looks like right now. It cannot easily tell you what it looked like in week 6, which is exactly what you need to judge whether a week 6 forecast was any good.

I wanted to build the analysis a sales analytics function would run on this: where pipeline really stands, where deals stall, and which forecast method deserves trust.

The data

The data is synthetic, modelled on a SaaS company that sells two ways: a self-serve product that users adopt on their own, and an enterprise sales team that closes the larger accounts growing out of it. It covers January 2024 to September 2026.

Real CRM data is messy, so I built the mess in on purpose: a Salesforce migration that cut off older history, duplicate account records, mixed currencies, missing deal amounts, deals past their close date and open deals still owned by reps who had left.

The approach

  1. Load and clean. Raw tables into PostgreSQL, then a staging layer that merges 140 duplicate accounts, standardises labels and converts everything to EUR. The SQL follows the raw, staging and marts layering used in dbt.
  2. Rebuild the past. A weekly snapshot of every deal as it stood each Monday, rebuilt from field history: 88 weeks and nearly 200,000 rows. This is the foundation for everything else.
  3. Measure pipeline health. Coverage against quota, stage conversion, time in stage, slippage and win rate by number of close-date pushes.
  4. Backtest the forecast. For every past week, predict the quarter three ways and compare with what actually closed.
  5. Make it usable. A Metabase dashboard and a one-page memo written for a VP of Sales.

The dashboard

Pipeline Health and Forecast dashboard in Metabase: quarter progress gauge, forecast error by week, coverage at quarter start, quota attainment, days in stage and win rate by close-date pushes
Open full size ↗ · Built in Metabase on the PostgreSQL models. Top: this quarter's progress and forecast accuracy. Below: why the quarters are being missed.

What the data showed

Not enough pipeline going in

Quota more than doubled, from €3.3M to €8.2M a quarter, while open pipeline stayed at €14–19M. Coverage at the start of the quarter fell from 5.4x to 2.3x. Only the quarter that started above 5x hit target; every quarter since finished between 79% and 97%.

The problem was not closing. It was what the team walked into each quarter with.

Deals that will be lost get stuck

Won deals move through each stage in about a week. Lost deals stay two to nine times longer, up to 75 days in Negotiation against 8 for won deals. Time in the current stage turned out to be the strongest single warning sign.

Close-date pushes are a signal, not noise

Close-date pushesWin rateReading
None31%Baseline
One44%Normal: dates move when deals are real
Two25%Worth a conversation
Three or more7%Polite, but not buying

Which forecast to trust

I compared three ways of predicting a quarter's bookings, each starting from what was already won and adding a view on the rest.

MethodHow it worksAverage error
Rep callsThe sum of each rep's weekly commit10–28%
Stage-weightedFixed probability per stage, the usual CRM default (10% to 80%)up to 64%
ModelLogistic regression on stage, time in stage, pushes, deal age and timing, plus the deals typically created mid-quarter1–9%
Line chart of average forecast error by week of quarter for rep calls, stage-weighted pipeline and the model
Average forecast error by week of quarter, across four completed quarters. Lower is better.

The model was trained walk-forward: each quarter was predicted only from the quarters before it, so it never saw the answer. I kept it to a logistic regression on purpose. In a pipeline review, "stuck 40 days in Proposal and pushed twice" is something a rep can act on.

Rep calls were not random either. Some reps consistently called about half of what they closed; others called two to four times as much. When a bias is that stable, leadership can adjust for it.

Current quarter, week 12 of 13
€7.1M closed against €8.2M quota. The team calls €8.5M. The model says about €8.1M: plan for on target, possibly just short.

What I would recommend

  1. Set a 3x coverage goal for week 1 of every quarter, tracked weekly from mid-way through the quarter before. The fix sits upstream, especially in product-led accounts, which win most often.
  2. Add two flags to the weekly pipeline review: deals more than three weeks in one stage, and deals pushed twice or more. Either give them a clear next step or take them out of this quarter.
  3. Show the model forecast next to rep calls, and review each rep's historical accuracy with them. Not to replace their judgement, but to show where it usually runs high or low.

Limitations

The data is synthetic, so the patterns are cleaner than a real CRM would give, and the forecast was tested on four quarters. On real data I would expect the model's lead over rep calls to be smaller, and I would validate it over at least two more quarters before anyone relied on it. With a live stack, the same models would sit in dbt on the warehouse, and product usage would feed both the forecast and lead scoring.

PostgreSQLSQLdbt-style layersPythonscikit-learnMetabaseDocker
SALES ANALYTICS · LAB

The code, data model, memo and dashboard are all open.

Next in this series: which self-serve users should sales talk to, using product usage to score accounts against the capacity of the sales team.

View the repository ↗ Read the one-page memo ↗ Back to the Lab