Most RevOps teams find out their CRM data is unreliable the same way: a forecast call where two dashboards disagree, or a board deck where the pipeline number does not match what sales actually believes is real. By then the bad data has already been driving decisions for months. A 2025 survey of 602 CRM users and administrators from Validity found that 76% of organizations say less than half of their CRM data is accurate and complete, and 37% say poor data quality has directly cost them revenue. The HubSpot UI will not surface that gap on its own. It is built to display records, not to interrogate them across thousands of rows at once.
Claude Code CLI, connected to the HubSpot CRM API, closes that gap. It can pull every contact, company, and deal object with its full property set, write its own comparison logic against the rules your team actually uses to define “clean,” and return a ranked list of exactly which records are broken and why. This is a walkthrough of how that audit works in practice, using a five-pass framework built for this specific job, not a generic data-cleaning checklist repurposed from spreadsheet work.
Why the HubSpot UI cannot run this audit
HubSpot’s native tools handle single-purpose jobs well: its duplicate management tool flags exact-match duplicates, and list filters can isolate records missing one property at a time. Neither was built to answer a compound, cross-object question in one pass.
- Duplicate detection is narrow. Native dedupe tooling catches close matches on name and email. It does a poor job with the harder case: two companies with different domains (a rebrand, a subsidiary, a typo’d URL) that are actually the same account, or contacts who match on a personal email at one company and a work email at another.
- Completeness checks are single-property. A saved list can show you contacts missing a lifecycle stage. It cannot easily show you contacts missing any two of five required properties, weighted by which properties actually matter for your lead routing.
- Stage aging has no cross-object context. HubSpot can sort deals by time-in-stage. It cannot cross that against the associated contact’s last engagement date and the company’s firmographic fit in the same view, which is usually what actually determines whether a stalled deal is dead or just slow.
None of that is a knock on HubSpot’s interface. It is built for a rep updating one record or a manager scanning one list, not for a full-CRM audit run against custom rules. That is a scripting problem, and a CLI session that can read the whole object set at once is the right tool for it.
The PULSE framework for a CLI-driven CRM audit
Five passes, run in order, each one narrowing from “is the data there” to “is the data trustworthy enough to report on.” The letters are a memory aid, not a rigid script. The order matters more than the name: you cannot meaningfully check stage aging against a contact record that might not actually be the real contact.
Pull. The session authenticates once against the HubSpot CRM API and requests the full contacts, companies, and deals object set with every custom property included, paginating through the results. This is the step a UI export cannot do cleanly: a CSV export truncates custom properties and associations that the API returns natively.
Unify. With every record loaded, the session runs a fuzzy match on company name, domain, and normalized address across the companies object, and a separate pass on contacts using name, phone, and email domain. HubSpot’s own dedupe catches near-exact matches. This pass catches the harder cases: a company whose domain changed after a rebrand, or two contact records tied to the same person under a personal and a work email.
Lifecycle. Rather than checking one property at a time, the session scores every contact against the full set of properties your lead routing actually depends on, whether that is five fields or twelve, and reports what percentage are missing at least one. This is where a generic “required fields” checklist usually undercounts the real gap, because most teams only enforce one or two fields at data entry and let the rest decay.
Stalled. For every open deal, the session compares current time-in-stage against the historical median for that stage and pipeline, then cross-references the associated contact’s last engagement date. A deal sitting in stage three for ninety days with a contact who opened an email last week reads differently than one with no contact activity at all.
Evidence. The recorded original source and attribution properties on each contact get checked against whatever first-touch signal is actually available, whether that is a stored UTM parameter, a form submission record, or an integration log. This is usually where the most consequential gaps show up, since a broken attribution integration can silently misassign months of pipeline before anyone notices.
A representative shape of what that output looks like, illustrative only:
That last line is the kind of finding a property-by-property review in the HubSpot UI is unlikely to surface, because nothing about a normal record looks wrong in isolation. It only shows up when the source property is checked against outside evidence at scale, which is exactly the kind of cross-object, cross-system comparison this workflow is built for. It is also the deeper layer sitting underneath a properly configured analytics MCP and API integration: the connection has to exist before an audit like this is even possible.
Where this does not replace judgment or native tools
- The output is a flag list, not an automatic fix. Merging two company records, correcting a lifecycle stage, or reassigning a deal’s source still needs a human decision, especially anywhere a merge could overwrite a legitimately different record.
- Read access first, always. The audit pass should run against the API in read mode. Any bulk write-back, such as a batch merge or a property update, is a separate, reviewed step, not something to chain onto the same session automatically.
- This is a snapshot, not a fix for decay. A clean audit today does not stay clean. CRM records decay on an ongoing basis as contacts change roles and companies rebrand, so this is a recurring pass, not a one-time project.
This same workflow extends past HubSpot. The pattern, pulling raw records through an API instead of a UI export and running custom comparison logic against them, is the same one we cover for GA4 investigation in Claude Code CLI and the GA4 Data API, and for joining that data to pipeline records in Claude Code CLI and BigQuery: A Practical Workflow for Pipeline Attribution Investigation. A CRM audit is usually the step that comes before either one, since attribution analysis built on top of unreliable source data just launders the same bad numbers into a more convincing-looking report.
Frequently Asked Questions
How do I audit CRM data quality?
Pull the full object set (contacts, companies, deals) through the CRM’s API rather than a UI export, since exports typically truncate custom properties and associations. Then run comparison logic for duplicates, required-field completeness, deal stage aging, and attribution accuracy, in that order, since later checks depend on earlier ones resolving which records are the real ones.
What should a CRM data quality audit check?
At minimum: duplicate rate across contacts and companies (industry guidance generally treats anything above 5% as a reporting risk), completeness against the specific properties your lead routing depends on, deals stalled well past a pipeline’s historical stage velocity, and whether the recorded source or attribution on closed deals actually matches available first-touch evidence.
How do I pull data from the HubSpot API for analysis?
HubSpot’s CRM API exposes contacts, companies, deals, and custom objects through authenticated REST endpoints, with each object’s full property set available by request rather than the fixed columns a UI export produces. A one-time private app or OAuth setup grants the access; after that, pulling and re-pulling data is a scripted, repeatable call rather than a manual export each time.
Is this safe to run against a production CRM?
Read access through the API does not modify records, so the audit pass itself carries no data-loss risk. The risk sits entirely in what happens after: a batch merge or bulk property update should always be a separate, reviewed action, not something executed automatically off the audit’s output.
How often should a CRM audit like this run?
CRM data decays continuously as contacts change roles, companies rebrand, and integrations occasionally fail silently, so a quarterly cadence is a reasonable floor for most B2B teams, with the Evidence (attribution) pass run monthly if the CRM feeds board-level pipeline reporting.
Want your CRM and analytics stack wired up for this kind of investigation instead of manual spot-checks? Book a call with MV3 to talk through what a PULSE-style audit would surface in your HubSpot portal.
Share this article
Ready to audit your organic growth opportunity?
$2,500 flat. 5 business days. Six deliverables tied to pipeline , not rankings. No retainer required.
Get the Organic Growth Audit →