Enrich your whole CRM with a join, not a queue

Your accounts already live in the warehouse. Canonical delivers the company universe alongside them, so enrichment becomes a dbt model you run on a schedule instead of a backfill job that grinds through a rate limit for a week.


01 — The problem

Where this breaks down today

Every revenue-data team ends up owning the same pipeline: take the account table, fill in industry, headcount, location, and funding, keep it current, and expose a clean view to sales and marketing. It sounds like an enrichment-API problem until you count the rows. At a few hundred thousand accounts, refreshed monthly, per-record calls stop being a line item and start being the architecture.

Bulk delivery flips the shape. The full company dataset lands in the same warehouse as your CRM extract, keyed on domain, and enrichment becomes a SQL join you can model, test, and re-run for free. The logic lives in dbt next to everything else, and coverage stops depending on which calls succeeded overnight.

Per-record enrichment does not scale with an account table. Refreshing 300,000 accounts means 300,000 metered calls, a queue, a rate limiter, a cache, and a retry policy — a small distributed system whose only job is moving rows one at a time. It runs for days, so the enriched table is never internally consistent: the first accounts were enriched against a different state of the world than the last. When a field is empty, you cannot tell whether the company genuinely has no value or the call timed out, and that ambiguity quietly poisons every segment built on top.


02 — Why bulk delivery

Why an API per record is the wrong shape

Enrichment is a join, and a join needs both sides in the same place. The moment your match rate matters — how many of your accounts the provider actually knows — you need to see the population, not query it row by row. Fuzzy matching on company name or domain variants is a set operation that is trivial in SQL and nearly impossible through an endpoint that answers one lookup at a time. And enrichment reruns constantly as your CRM changes, so a metered per-row model charges you again for data that did not move.


03 — How it works

How Canonical solves it

Canonical delivers the complete company dataset into Snowflake via Secure Data Sharing, as a shared BigQuery dataset, or to your S3 bucket in Apache Parquet. Join it to your account table on domain and every enriched field is available at once — firmographics, headquarters, headcount, funding history, investors, and founders — with no call budget and no partial-failure handling. Because you can see both sides, you can measure match rate honestly, resolve the accounts that did not match on your own terms, and tell a genuine null apart from a missing lookup. Each delivery replaces the last, so the refresh is a re-run of the same model rather than a reconciliation.

  1. Point us at your warehouse

    Tell us where your CRM data already lives — Snowflake, BigQuery, or S3 — and which attribute groups your go-to-market team actually uses. We send a sample dataset so you can test the join before committing.

  2. Join on domain

    The dataset arrives keyed on company domain, the field your CRM already stores. Enrichment becomes a dbt model beside your other transformations, with match rate and coverage visible as ordinary SQL.

  3. Re-run it every delivery

    Weekly, monthly, or quarterly, each snapshot fully replaces the previous one. Rebuild the enriched view on a schedule and every downstream segment and dashboard updates with it.


04 — What's delivered

The attributes this use case relies on

Attribute groups, not an exact schema — the delivery schema is finalized with you during onboarding. See everything a delivery contains.

  • company

    Canonical name, domain, founding year, and description.

  • headquarters

    City, region, and country of the primary HQ.

  • firmographics

    Industry, business model, and offering attributes.

  • employee_count

    Latest estimated headcount.

  • funding

    Total raised, round count, and the latest round's series, date, amount, and lead investor.

  • investors

    Known investors across the company's funding rounds.


05 — FAQ

Frequently asked questions

Why not just use an enrichment API for my CRM?

For a few thousand accounts, do that — it is simpler. Bulk delivery starts paying off when the table is large enough that per-record calls force you to build a queue, a rate limiter, and a retry policy, or when you need to re-enrich often enough that paying per row each time stops making sense.

What do you join on?

Company domain is the primary key and the field CRMs most reliably hold. The dataset also carries canonical company names and known domain variants, so accounts recorded under an old brand or a country-specific domain can still be matched with your own SQL.

Does it write back into Salesforce or HubSpot?

No. Canonical delivers data into your warehouse; the write-back is yours to run, with whatever tool already syncs your warehouse to your CRM. That is deliberate — it keeps your field mapping and overwrite rules under your control.

How do I know the match rate before buying?

Test it on the sample. Book a demo, join the sample dataset against your own account table, and measure coverage on your real accounts rather than on a published figure. That is the number that decides whether this is worth it.

Will it cover our long-tail and non-US accounts?

Coverage of the long tail is the reason most teams look at Canonical in the first place — smaller, newer, and non-US companies that mainstream databases skip. The honest way to confirm it for your specific book of business is to run the sample against your own accounts.


Start with a sample dataset.

Tell us what you're building and we'll scope the delivery around it, then send a sample so you can test the join before committing to anything.

Book a demo