Attribution & AnalyticsGuideIntermediate

Offline conversions from your CRM: uploads with the original timestamp, hashed identifiers and honest values

How to feed CRM outcomes — qualified leads, closed deals, in-store purchases — back to Google Ads, Meta, LinkedIn, TikTok and Microsoft through Track's import source, which identifiers each platform needs and which timing rules apply.

By
Track editorial team
Published
Last reviewed
Reading time
3 min read

Key takeaways

  • Export one row per CRM outcome, send it to the server event endpoint with a CRM source key, and it becomes a canonical event with the original timestamp and the recorded consent state.
  • Normalise and hash identifiers before sending; rows with plain identifiers fail validation, and an event without consent information reaches no advertising destination.
  • Each platform has its own mechanism, required identifier and time rules; upload the time the outcome happened, never the export time.
  • Store click ids on the lead for deterministic matching, keep values real, documented constants or empty, and send downstream outcomes as their own events rather than duplicating the browser's.

The workflow

  1. Export from the CRM: one row per outcome with the outcome time, the identifiers you have (e-mail, phone, click id if stored on the lead, order id) and the value.
  2. Send the rows to the server event endpoint with a source key created for the CRM. Each row becomes a canonical event (qualified_lead, purchase, refund, subscribe) with props.offline: true, the original timestamp and the consent state your system recorded for that person. A small script or the CRM's outbound webhook can do this; the endpoint accepts batches and answers with the number accepted or a validation error that names the field.
  3. Normalise and hash before sending: e-mails lowercased and trimmed, phones converted to E.164, then SHA-256. Rows that arrive with plain identifiers fail validation; nothing is hashed on your behalf.
  4. Route exactly as browser events: the policy engine applies the consent state carried by the event, per destination. An event without consent information carries only the necessary purpose and reaches no advertising destination.
  5. Deliver through the same connectors, with the offline variants of each API.

The event debugger shows every imported event with its source, and the destination monitor shows the delivery status per destination.

Per platform

PlatformMechanismRequired identifierTime rules
Google Adsclick conversion uploadgclid/gbraid/wbraid or hashed e-mail/phone (Enhanced Conversions for Leads)after the click, inside the window; not older than the action's click-through window
MetaConversions API with action_source: physical_store or system_generatedhashed e-mail/phone, external_id; fbc if storedwithin 62 days
LinkedInConversions APIhashed e-mail or li_fat_idwithin 90 days
TikTokEvents API with event_source: offline and an offline event set idhashed e-mail/phonewithin 7 days for web, longer for offline sets
MicrosoftConversions APImsclkid or hashed e-mail/phoneinside the goal's window
Affiliate networkspostback with the stored click idnetwork click idper programme

The timestamp you upload must be the time the outcome happened, not the time you exported it. Uploading yesterday's deals with today's timestamp shifts attribution and can put conversions outside the click window.

Store the click id on the lead

Matching by click id is more reliable than by hashed e-mail. Copy the click-id parameters from the landing URL (gclid, msclkid, fbclid, li_fat_id, ttclid) into hidden form fields when marketing consent is granted, and store them on the lead in the CRM. Later, when the lead closes, the export carries the click id and the upload matches deterministically.

Values: model them or leave them empty

A qualified lead has no order value. Options that stay honest:

  • Leave the value empty; count-based optimisation still works.
  • Use a documented expected value per lead stage (for example, average deal size × close rate), set in the destination mapping as a constant and visible in the audit log.
  • Upload the actual deal value when the deal closes, as a separate conversion.

What Track will not do is invent a value: unmapped values stay null, and a mapping that references a missing property fails validation instead of substituting a default.

Deduplication with browser events

Do not send the CRM's "form submitted" row as the same event the browser already sent; you would double count unless the event id travels with the lead. Send downstream outcomes (qualified_lead, purchase) as their own events, mapped to separate conversion actions or rules. For purchases that the browser also saw, keep the order id on both so platforms that dedupe on order id merge them.

Checklist

  • To do: Export contains outcome time in ISO 8601 with a time zone
  • To do: Identifiers normalised before hashing; already-hashed columns marked as hashed
  • To do: Click ids stored on the lead at form submission
  • To do: Values either real, documented constants or empty
  • To do: Batch responses reviewed: rejected rows fixed, delivery per destination confirmed in the destination monitor

Primary sources

Documentation and standards this article is based on.

  1. Google Ads Help — About offline conversion importssupport.google.com
  2. Meta for Developers — Conversions API for offline eventsdevelopers.facebook.com

Was this article helpful?

Responsible editor

Track editorial team

Product & engineering

The people building Track: engineers and analysts who work on server-side tracking, consent tooling and connector integrations every day.