# Tracking, Attribution, and Enrichment



An SDK form reports the same funnel signals a hosted form does, almost all of it automatically.

## Vendor tracking [#vendor-tracking]

When the form's settings carry tracking IDs, the SDK bootstraps the vendors and fires the same events as native forms: `SurfaceFormStarted`, `SurfaceFormStepSubmitted`, and `SurfaceFormSubmitEvent` on GTM's dataLayer, Meta `trackCustom`, and GA4 events.

* **Configure** in the dashboard (Tracking & Analytics) or over MCP with `update_form_settings` (`gtmId`, `gaMeasurementId`, `metaPixelId`, `trackPartialResponses`, `trackCookie`). Ad conversion rules and HubSpot tracking are dashboard-only.
* **Or pass at init**: `SurfaceForms.init({ settings: { gtmId, gaMeasurementId, metaPixelId, adsConversions } })`. Caller values win.

Ad conversion rules fire once per rule per response, queue until the first save produces a `responseId`, and terminal rules fire on completion only, never on disqualify. A booking fires the `meeting_booked` trigger.

**Verify on a deployed page**: complete a step, inspect `window.dataLayer` for `SurfaceFormStepSubmitted`. Preview mode blocks tracking entirely. `form.capabilities.tracking` reports whether tracking is active.

## Lead journey and attribution [#lead-journey-and-attribution]

All on by default:

* **Page-view journey**: the `journey` option tracks page views with the same cookies the Surface Tag uses and stamps the journey ID onto every response. Pass `journey: false` only where the Surface Tag already runs, to avoid double-counting.
* **URL attribution**: the form's URL, query parameters (UTMs), and referrer ride every save.
* **Visitor identity**: `init` identifies the visitor in the background with the Surface Tag's identity cache; boot never waits, the first save does. After an SPA route change, call `form.identify()`.

## URL prefill [#url-prefill]

Same prefill query syntax as hosted forms: `?<questionId>_<fieldName>=value` seeds an answer (splits on the first underscore; `url`, `referrer`, `cookies` are reserved).

## Real-time enrichment [#real-time-enrichment]

With an enabled enrichment provider, a valid email or website domain on the record's enrichment source field triggers enrichment, and the result rides every save as enriched lead attributes. Deduplicated per value, never fired in preview.

<Warning>
  No enabled provider means enrichment is silently inert, even if the record declares a source field. Check `form.capabilities.enrichment`; `debug: true` warns about the mismatch at boot.
</Warning>

To autofill your own inputs from the result, read `state().externalStates.selfServeEnrichment.data` via `subscribe`.

## What lands on the response [#what-lands-on-the-response]

* Every answer, shaped as the binding map's `answerShape`.
* `meta.surfaceTagStatus: "sdk"` (distinguishes SDK from hosted submissions).
* `meta.userJourneyId` plus the stitched page-view journey.
* URL, UTM parameters, and referrer.
* Email validation verdicts, enriched fields, and `meta.custom` values from `mergeMeta`.
