The problem
In B2C, the person who clicks the ad is usually the person who buys — attribution just follows one contact. B2B breaks that assumption. Accounts payable pays the invoice; a developer on the same team clicked the ad and signed up for a free trial weeks earlier using a personal Gmail address. Grouping contacts by email domain can’t connect them, because the payer’s and the developer’s email domains don’t match, or neither address is a business address at all. What you actually want is CRM-style account-level attribution: group every contact that belongs to the same customer account together, so a conversion by one teammate can be credited to the ad another teammate clicked.company_external_id is how you tell Cometly which contacts belong to the same account.
Prerequisites
- A Cometly API key.
- A Space.
- The Space’s Company identity mode set to “Group by your account ID” (External ID), in Space Setup → Additional Setup → Company Tracking. The other mode, “Group by email domain” (Auto), is the default and ignores
company_external_identirely.
company_external_id is still accepted on events and stored — it’s just ignored for grouping. If your events already carry the field while the Space is in Auto mode, the Company Tracking settings page shows a warning banner telling you so, so you don’t spend time debugging a company grouping that was never turned on.
The identifiers, contrasted
Three fields on Create Event sound similar but do unrelated jobs. Mixing them up either merges contacts that shouldn’t be merged, or fails to group the account at all.company_name rides alongside company_external_id as a fourth field: it’s a display-only name for the company, last write wins, and it’s never used for matching — two companies with the same name stay separate. It’s ignored unless company_external_id is also sent, since the name alone doesn’t identify a company.
Send it on every event
Sendcompany_external_id on every event a member of the account triggers — sign-up, trial activation, purchase, whatever your funnel tracks — alongside a per-user tracking_id, a unique idempotency_key, and optionally company_name. Normalization rules for company_external_id and company_name: trimmed, case preserved (never lowercased), stored byte-exact, 1–190 characters (company_external_id) or 1–255 characters (company_name) after trimming, and integers are accepted. A blank string is treated as absent (null); floats, arrays, and booleans are rejected with a 422.
A developer signs up with a personal address:
company_external_id, different contact:
company_external_id, so once External ID mode is on, both contacts land in the same company — even though they never share a tracking_id, an email domain, or a name.
Send it via webhooks or Stripe metadata
If you’re sending events through a webhook instead of the API directly,Company External ID and Company Name are available as mapping destinations in the webhook mapping step, alongside your other field mappings.
For Stripe specifically, your account ID typically travels in the object’s metadata rather than as a top-level field. Map the source field data.object.metadata.<your key> (for example data.object.metadata.account_id) to the Company External ID destination, and optionally another metadata key to Company Name.
The source-field dropdown in the mapping step is only populated from the sample payloads Cometly received while you were setting up the webhook (Check for Data). If your metadata key wasn’t present on any of those sample events, it won’t show up as an option. Send a test event carrying the metadata key first, then re-run Check for Data, before mapping it.
Timing: send sign-up events in real time
Ad-platform conversions (CAPI) go out roughly 14 minutes after the conversion itself. For a teammate’s ad click to be picked up when accounts payable’s purchase is sent to Meta or Google, the developer’s account membership (theircompany_external_id) needs to already be recorded by then. Send sign-up and membership events in real time as they happen, not batched into a nightly job — a sign-up event that arrives after the conversion it should inform has already been sent is too late to change how that conversion was attributed.
Turn on ad-platform conversion identity = company
Company grouping alone doesn’t change who a conversion is attributed to when it’s sent to Meta, Google, and the other ad platforms — it only groups contacts for reporting. To also redirect the ad-platform conversion’s identity to the right teammate, turn on the second Company Tracking setting: Ad-platform conversion identity → “Send as the teammate who clicked the ad” (company mode, on the same Company Tracking page).
With this on:
- A conversion is sent under the identity of the teammate in the same company whose ad click is the most recent before the conversion — their email, name, phone, and click IDs. It’s always one person’s identity, never a blend of two people.
- If no teammate in the company clicked an ad more recently, the conversion falls back to being sent as the person who actually converted.
- It never changes conversion facts:
amount,order_id, and the conversion time are always the real ones. - It requires company grouping — a contact with no company (in either identity mode) is always sent as themselves.
Fix a grouping, or link a contact that never sends events
Some contacts never send an event carryingcompany_external_id at all — an inbound lead created via CRM sync, for instance. Two endpoints let you fix that without waiting for another event:
- Update Company — set or change a company’s
external_iddirectly. - Attach Contact Company / Detach Contact Company — move a contact onto a company, or off it entirely.
company_external_id re-points the contact again either way.
Read it back
- Get Company and List Companies both return
external_idalongsidedomainandname. - The Companies dataset in the data warehouse carries
external_idas a column — join on an exact match against your own account IDs. - If you’re enabling External ID mode on a Space that already has history, run a one-time export over all history on the Companies dataset. Incremental exports are windowed on
created_at, so a company that gains anexternal_idafter its original creation window won’t be re-exported by a recurring run.
Reality note
Cometly groups companies by business-email domain (Auto mode) or by your owncompany_external_id (External ID mode) — it does not read association data from HubSpot, Salesforce, or any other CRM’s company/account records. If you need Cometly’s company grouping to match your CRM’s account structure, send that CRM’s account identifier as company_external_id on every event, rather than expecting CRM associations to be picked up automatically.