GA4’s built-in attribution reports show one model at a time. When you want to compare how your conversions would be credited under different attribution models — first-touch, last-touch, linear, and data-driven — you need BigQuery. This guide shows you how to implement multiple attribution models in SQL and understand the strategic differences in the results.

Why Attribution Model Comparison Matters

  • Last-touch (GA4 default): Google Search gets credit as the last click before purchase — even if Facebook introduced the customer
  • First-touch: Facebook gets credit for introducing the customer
  • Linear: Credit split equally across all touchpoints
  • Data-driven: Credit weighted by statistical contribution from your own conversion data

Building User Journey Touchpoints

-- Build user touchpoint journeys with ordering
WITH touchpoints AS (
  SELECT
    user_pseudo_id,
    event_timestamp,
    COALESCE(
      (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source'),
      traffic_source.source
    ) as source,
    COALESCE(
      (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'medium'),
      traffic_source.medium
    ) as medium,
    ROW_NUMBER() OVER (PARTITION BY user_pseudo_id ORDER BY event_timestamp ASC) as touch_number,
    ROW_NUMBER() OVER (PARTITION BY user_pseudo_id ORDER BY event_timestamp DESC) as reverse_touch_number,
    COUNT(*) OVER (PARTITION BY user_pseudo_id) as total_touches,
    MAX(CASE WHEN event_name = 'purchase' 
      THEN (SELECT value.float_value FROM UNNEST(event_params) WHERE key = 'value') 
      ELSE 0 END) OVER (PARTITION BY user_pseudo_id) as conversion_value,
    MAX(CASE WHEN event_name = 'purchase' THEN 1 ELSE 0 END) 
      OVER (PARTITION BY user_pseudo_id) as is_converting
  FROM `project.dataset.events_*`
  WHERE event_name IN ('session_start', 'purchase')
  AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAYS))
)
SELECT * FROM touchpoints WHERE is_converting = 1;

First-Touch Attribution

-- First-touch: credit to first touchpoint
SELECT
  'first_touch' as model,
  CONCAT(source, ' / ', medium) as channel,
  SUM(conversion_value) as attributed_revenue,
  COUNT(DISTINCT user_pseudo_id) as attributed_conversions
FROM converting_journeys
WHERE touch_number = 1
GROUP BY source, medium
ORDER BY attributed_revenue DESC;