CRM & data

Why your CRM reporting disagrees with finance

It is almost never the CRM. A join key nobody retired, a table built for one board meeting, a stage that counts quotes as orders. The five causes I find, with the six-figure example that came from one of them.

It is almost never the CRM. When the pipeline number on the dashboard and the revenue number finance signs off disagree, the records in the CRM are usually correct when you check them one account at a time, and the gap comes from a join key, a stale table, a stage definition or a sync, one of five places rather than everywhere.

I spent a stretch of this year inside exactly this problem for a B2B SaaS platform, where leadership could not trust the revenue board and nobody could prove which figure was right. The core data reconciled to the penny on the control accounts I checked. The forecast was still wrong by six figures. Here is where that came from, and the other four places I look.

What was actually wrong?

The forecast panels were keyed on a legacy customer identifier, which had been the way the product linked a customer to their orders until matching moved to the company domain. Nobody retired the old key. It was empty for the large majority of companies, and the forecast joined on it anyway, so any customer who had come in since the change simply did not exist as far as the forecast was concerned.

That dropped dozens of active customers, worth seven figures of orders across their lifetime and a six-figure chunk of the quarter being forecast. Some of the names missing were among the largest accounts on the platform.

Repointing the join onto the domain moved the quarter’s forecast up by an amount that matched the audited exposure almost exactly. A correction, not growth, and it went to the board the same day with the explanation attached.

The point is not the size of the number. It is that the CRM was right the whole time. The customers were in there, with their orders, reconciling to the product source exactly. One join in one reporting layer made them invisible.

The five places I look

Cause What it looks like from the outside How you catch it
A legacy join key A total that is too low by a lump, with recent customers missing Count nulls on every key used in a join. Anything over a few percent null is not a key
A snapshot table nobody refreshed History that stops on one date, or one account wildly under-reported Check the sync timestamp. If every row shares one, it is a snapshot
A stage or lifecycle definition Accounts promoted too early, pipeline value inflated Read the workflow that sets the stage and compare its filter to the product’s own definition
A sync that drops columns or values A report that used to work and now shows nothing, or multi-domain companies not matching Pin the schema explicitly. Autodetect deletes all-null columns without telling you
Pace maths on the wrong dates A quarter that reads far more behind than the team believes Find out who sets the target date. If the system stamps it, the pacing is fiction

All five turned up in the same instance, which is normal. They accumulate, because each one was reasonable at the time and nobody was paid to go back.

The table built for one board meeting

The second biggest gap came from a quarterly revenue table that turned out to have been built once, on a single date, as a workaround to get a number for a board pack. Every row shared one sync timestamp. It was never refreshed, it was set to delete itself a couple of months later, and two live panels were still reading history off it.

Even within its own snapshot it was incomplete. One quarter showed a fraction of the revenue its own order count implied, and one large account showed a few thousand in the table against seven figures live. Anyone reading a trend off that table was reading a trend in when it had been built.

The fix was a small scheduled job that aggregates orders by company and quarter from the product database directly, keyed on domain, into one table in the same dataset the dashboard already reads from. No new database, no new entity. Validated against the business’s own historic reporting, which agreed to within a fraction of a percent once the quarter boundaries were aligned on the same date field.

When a quote counts as an order

The lifecycle stages were promoting accounts on order count, which sounds right until you find that the count included quote requests. One account had a handful of order records in the product, fewer than half of them real orders and the rest old quotes, and it was staged as a top-tier customer on the strength of all of them.

The attributes were fine. The stage definition was wrong. The product’s own order model defines a real order as a specific set of statuses, ordered through delivered, and excludes drafts, quotes, holds, cancellations and declines. The stage workflow was not using that set. Pointing it at the product’s own definition fixed the promotions, and it also exposed that the value tiers were labelled as if they were annual when the logic underneath was all-time cumulative spend.

The general lesson: when a CRM stage disagrees with what finance would call a customer, read the workflow that sets the stage. It is usually years old and was written before the definition existed.

The pacing number that frightened everyone

The quarter first read as more than half behind target. It was actually about a quarter behind, which is a different conversation to have with a board.

Two things produced the gap. Target dates on open opportunities were being stamped automatically by the system rather than set by the reps, so the pacing calculation was comparing progress against dates nobody had chosen. And the pace maths pro-rated open opportunities by calendar time in a way that assumed linear delivery, which for a business with lumpy orders is not how the quarter arrives. Fixing both, with the founder in the room for the target date decision, brought the number to something the team recognised.

What good looks like afterwards

The rule that came out of it is simple to state. Reporting reads product truth end to end. Every revenue and forecast number on the dashboard comes from the product’s own order data through the reporting layer, and the CRM is fed from the same source, so a bug in the push to the CRM can never become a bug in a board number.

Underneath that, four habits keep it honest. Control accounts reconciled by hand and rechecked after every change. A pinned schema on every sync so columns cannot vanish. A daily drift check that compares the CRM to the product and reports a match rate, so regressions are detected rather than rediscovered in a board meeting. And every definition, real order, active customer, quarter boundary, written down once and used everywhere.

None of this required a new tool. It required someone to read the joins.

If your dashboard and your finance team disagree and nobody can say why, that reconciliation is the first thing I do in a CRM and data audit.

Frequently asked

Why does my CRM revenue not match my finance numbers?
Usually because the two are counting different things through different joins. The most common causes are a legacy identifier still used as a join key, a snapshot table that was never refreshed, a stage or lifecycle definition that counts quotes as orders, and a sync that silently drops columns. The CRM records themselves are usually fine when you check them one account at a time.
How do I find out which number is right?
Pick three accounts and reconcile them by hand, from the product or billing source through to the dashboard. If the accounts tie out to the penny at the record level and the total is still wrong, the problem is in a join, a filter or a stale table, not in the data. That narrows it from everything to about five places.
Should the CRM be the source of truth for revenue?
No. Revenue truth lives in the system that took the order or the payment. The CRM should be fed from it, and the reporting layer should read the product or billing data directly, so a bug in the push to the CRM can never become a bug in a board number.
What is a control account?
An account you reconcile completely by hand and keep as a reference. If your control accounts match to the penny after every change to the reporting, you know the pipeline is sound and any remaining gap is definitional. If they stop matching, you know exactly when something broke.

Think your CRM data is costing you deals?

A short call is the fastest way to find out. I will tell you straight whether there is something worth fixing, and the paid audit is where the proper diagnosis happens.

Book a 15-minute intro call

Or see how I work with CRM and data →