Skip to Content
How It Works

How It Works

AttributionHub works in four stages on every page load: detect, classify, store, and populate.

The Attribution Pipeline

Page Load | v 1. DETECT -- Read URL params, referrer, click IDs | v 2. CLASSIFY -- Determine channel group (Paid Search, Organic Social, etc.) | v 3. STORE -- Save touch snapshot to localStorage | v 4. POPULATE -- Fill form fields with attribution data

Stage 1: Detect

When a page loads, the script reads:

  • URL parametersutm_source, utm_medium, utm_campaign, utm_content, utm_term, and any custom fields
  • Click IDsgclid (Google), msclkid (Microsoft), fbclid (Meta), ttclid (TikTok), li_fat_id (LinkedIn), and more
  • Referrer — the document.referrer URL
  • Landing URL — the current page URL and path

Stage 2: Classify

Using the detected signals, the script classifies the visit into one of 20+ channel groups using a priority-based rule system:

  1. Check for explicit channel signals (e.g., utm_medium=cpc with a search source = “Paid Search”)
  2. Check for click IDs (e.g., gclid present = likely Google Ads)
  3. Match the referrer against known domains (200+ search engines, 80+ social networks, 18+ AI assistants)
  4. Fall back to medium-based classification
  5. Default to “Direct” (no referrer, no UTMs) or “Referral” (unknown external referrer)

See Channel Detection for the full classification logic.

Stage 3: Store

The classified data is saved as a touch snapshot in localStorage. Three snapshots are maintained:

Touch TypeKey PrefixBehavior
First Touchah_ft_The first non-direct visit. Locked permanently once set. Never overwritten.
Latest Touchah_lt_Updated on every page load, including direct visits.
Latest Non-Directah_lnd_Updated only when the visit comes from an external source. Preserved across direct revisits.

Additional stored values:

  • ah_visitor_id — a unique UUID generated on the first visit
  • ah_touch_count — total number of visits

Stage 4: Populate

The script discovers forms on the page and fills matching hidden fields with attribution data. A two-tier handler architecture ensures broad platform coverage:

  1. Specialized handlers run first — dedicated handlers for platforms that use iframes, SDK APIs, or cross-origin messaging (HubSpot, Marketo, Pardot, ActiveCampaign, Calendly, Typeform, Zoho, Jotform, Webflow, Contact Form 7). Each marks populated forms with data-attrhub-populated.
  2. Standard handler runs last — scans for all <form>, .form, [role="form"], [data-form] elements (plus any custom selectors from settings.formSelectors), skipping forms already populated by a specialized handler.
  3. Sets field values and dispatches change/input events for framework reactivity
  4. Retries after ~500 ms for dynamically loaded forms
  5. Watches the DOM via MutationObserver for newly inserted forms (SPA support)

All handlers honour settings.fieldMapping — no handler hardcodes attribution field names.

Touch Snapshot Lifecycle

Here’s how the three touch types behave across multiple visits:

Visit 1: Google Ads click first = { channel: "Paid Search", source: "Google" } latest = { channel: "Paid Search", source: "Google" } latestND = { channel: "Paid Search", source: "Google" } Visit 2: Direct (typed URL) first = { channel: "Paid Search", source: "Google" } -- unchanged latest = { channel: "Direct", source: "Direct" } -- updated latestND = { channel: "Paid Search", source: "Google" } -- preserved Visit 3: LinkedIn organic post first = { channel: "Paid Search", source: "Google" } -- unchanged latest = { channel: "Organic Social", source: "LinkedIn" } latestND = { channel: "Organic Social", source: "LinkedIn" } Visit 4: Direct (bookmark) first = { channel: "Paid Search", source: "Google" } -- unchanged latest = { channel: "Direct", source: "Direct" } -- updated latestND = { channel: "Organic Social", source: "LinkedIn" } -- preserved

The script determines if traffic is paid by checking for these signals:

  • Medium keywords: cpc, cpm, cpv, cpa, ppc, retargeting, sem, boosted, influencer, display, banner, native
  • Medium prefix: starts with paid (e.g., paid-social, paid_search)
  • Click IDs: gclid, gbraid, wbraid, msclkid, fbclid, ttclid, li_fat_id, twclid, snapclid
  • Google Ads signal: gad_source parameter present

If any of these are detected, the visit is marked as paid, and the channel classification shifts to the corresponding paid variant (e.g., “Organic Social” becomes “Paid Social”).

Direct Visit Handling

A visit is classified as Direct when:

  • No referrer is present (document.referrer is empty or same-domain)
  • No UTM parameters are set
  • No click IDs are detected

Direct visits update the latest touch but intentionally do not overwrite the first or latestNonDirect touches. This ensures that the original marketing source is preserved even when a visitor returns by typing the URL directly.

Conversion Tracking

When a form is submitted, AttributionHub captures conversion metadata:

  • Timestamp — when the conversion happened
  • URL and path — where the conversion occurred
  • Event name — the form identifier or event type
  • Days to convert — time between first visit and conversion

This data is stored as ah_conv_* fields and included in the form submission.