Attribution & AnalyticsGuideIntermediate

Lead generation tracking for B2B: from form submit to closed deal without double counting

A tracking design for B2B sites — generate_lead, contact and book_appointment events, hidden click-id fields, hashed business e-mails, qualified-lead uploads from the CRM and separate conversion actions per stage — with the consent rules that apply at each step.

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

Key takeaways

  • Each funnel stage — form submit, demo booked, qualified lead, closed won — is its own event and its own conversion action or rule, which is what prevents double counting.
  • Fire generate_lead on successful submission, call identify with the business e-mail only after marketing consent, and copy click ids into hidden form fields stored on the lead.
  • The CRM sends qualified_lead with the original click ids, the hashed e-mail and the stage timestamp; closed deals become purchase with the real value, sent from the server.
  • The consent recorded at submission travels with every later upload: a lead that refused marketing is never uploaded to advertising platforms, and values are real or documented constants, never backfilled.

The stages, and the event for each

StageWhere it happensCanonical eventSent by
Form submittedbrowsergenerate_lead (lead_type, form_id)SDK, hybrid with vendor pixels
Demo bookedbooking toolbook_appointmentSDK on confirmation, or webhook
Contact requestbrowsercontactSDK
Marketing qualifiedmarketing automationqualified_lead (custom, declared)server source
Sales qualified / opportunityCRMqualified_lead with stageserver source
Closed wonCRMpurchase with value, transaction_idserver source

Each stage is its own event and, in the ad platforms, its own conversion action or rule. That is what prevents double counting: nothing is sent twice under the same name from two sources.

Step 1: the form

  • Fire generate_lead on successful submission, not on button click. For AJAX forms, on the success callback; for full-page redirects, on the thank-you page with a guard against reloads.
  • Include form_id and lead_type (demo, whitepaper, contact), nothing free-text.
  • Call identify with the business e-mail after marketing consent. The SDK hashes it before it leaves the browser and attaches it as em for the platforms that match on hashed e-mail (Meta, LinkedIn, Google Enhanced Conversions for Leads, Microsoft, TikTok).

Step 2: carry the click ids into the CRM

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 record together with the landing page and the consent state at submission. Weeks later, these are what make an upload match deterministically instead of relying on e-mail hashing alone.

Step 3: qualified leads from the CRM

When a lead reaches a stage worth optimising for, the CRM sends a server event: qualified_lead with the stage, the original click ids, the hashed e-mail and the stage timestamp. Each platform receives it on its own conversion action:

  • Google Ads: uploadClickConversions with gclid or hashed e-mail, conversion action "Qualified lead (CRM)".
  • LinkedIn: Conversions API with SHA256_EMAIL or li_fat_id, rule "Qualified lead", within 90 days.
  • Meta: Conversions API Lead with action_source: system_generated, on a separate custom conversion so the pixel Lead stays separate.
  • Microsoft: CAPI with msclkid or hashed e-mail, goal "Qualified lead".

Step 4: closed won as purchase

The deal value is real now. Send purchase with value, currency and the CRM opportunity id as transaction_id, from the server, with the close date as the event time. Platforms that support value-based bidding get the actual number; those that do not still count the conversion.

  • The form and its generate_lead need marketing consent for advertising destinations; analytics-only consent still records the event for your own reporting.
  • Click ids are captured only with marketing consent. Without it, the CRM stage uploads can only use hashed e-mail, and only if the person consented to that use at submission — record the consent state on the lead.
  • CRM uploads carry the consent state you recorded at submission; the policy engine routes accordingly, and an upload without consent information reaches no advertising destination. A lead that refused marketing at the form is not uploaded to advertising platforms later, however valuable.

Values without inventing them

For qualified_lead, either send no value or a documented expected value per stage configured as a constant in the destination mapping. For purchase, send the real deal value. Never backfill a value into generate_lead; the platforms will optimise toward whatever you send, and a fabricated number optimises toward fiction.

What to look at weekly

  • Health score coverage: generate_lead seen on every form id in the plan.
  • Destination monitor: upload acceptance per platform; CLICK_NOT_FOUND and out-of-window errors point at missing click ids or late uploads.
  • Consent page: share of leads with marketing consent — the ceiling for what advertising platforms can ever see.

Primary sources

Documentation and standards this article is based on.

  1. Google Ads Help — Enhanced conversions for leadssupport.google.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.