Last-click attribution doesn't say your blog drove zero revenue. It says something more specific and more damaging: it hands every sale to whatever channel happened to be there at the final click, which is usually branded search, direct, or paid. Content does its work early, gets no click at the moment of purchase, and disappears from the revenue report even though it started the journey. Multi-touch attribution (MTA) spreads credit across every touchpoint on the path instead of the last one, and you can build a working version of it from your GA4 BigQuery export without buying an enterprise platform. This post covers the models, their tradeoffs, the SQL, and the honest limits of the whole exercise.
What last-click actually does to content
Be precise about the mechanism, because the loose version of this argument gets picked apart in finance meetings.
Last-click doesn't ignore content that gets the final click. A bottom-of-funnel comparison page that someone clicks and then converts gets full credit under last-click, and does fine. The channel last-click punishes is the one that influences a decision without being present at the checkout. Someone reads your guide in week one, leaves, thinks about it, returns three weeks later by typing your brand into Google, and converts. GA4's default records that as a branded organic or direct conversion. The guide that created the demand gets nothing.
This has always been true. What's changed is how much of the early journey is now invisible. AI answer engines resolve a growing share of research-stage questions without ever sending a click, so the top-of-funnel touch that content used to at least register as a session increasingly doesn't happen on your site at all. The reporting problem and the AI problem compound: more of the buyer journey happens before anyone lands on your site, and the part that does land is credited to a later channel.
The practical consequence: teams measured on last-click revenue systematically underinvest in the content that fills the top of their own funnel, because the report tells them it isn't working.
Why you can't just fix this in GA4's interface
Here's the correction to the standard advice you'll see repeated in most MTA articles, including the version implied by this post's own brief.
You cannot switch GA4's UI to linear, time-decay, or position-based attribution. Those models no longer exist in the interface. In late 2023 Google removed first-click, linear, time-decay, and position-based from GA4, and migrated existing properties to data-driven. Two models remain selectable: data-driven attribution and last-click. Google closed the same loophole in Google Ads in mid-2026, force-migrating any conversion action still running the old models.
So the advice "compare linear versus time-decay in GA4" describes a product that hasn't existed for over two years. You have two real options. Use GA4's data-driven model, understanding what it is and isn't. Or rebuild the rules-based models yourself in BigQuery, which is the only way to actually see and control the credit split. This post does the second, because the first is a black box.
The models, and what each one is good for
Five rules-based models, each answering a slightly different question. None is "correct." Each is a lens.
First-touch. All credit to the first interaction. Answers "what introduced this customer to us." Good for measuring awareness content, useless for anything past the top of the funnel, since it ignores everything that closed the deal.
Last-touch. All credit to the final interaction. Answers "what was present at conversion." GA4's fallback. Good for bottom-funnel optimization, structurally blind to everything that built the demand.
Linear. Equal credit to every touch. Answers "which channels appeared on winning paths at all." Simple and defensible, but it overcredits low-value touches, a stray navigation session counts as much as the guide that did the persuading.
Time-decay. More credit to touches closer to conversion, on a configurable half-life. Answers "what moved them as the decision neared." Reasonable default for sales cycles with a clear closing phase. It structurally underweights early content, which is the exact thing you're often trying to prove, so it's a conservative choice that won't be accused of inflating top-of-funnel.
Position-based (U-shaped). Usually 40% to first touch, 40% to last, 20% split among the middle. Answers "what introduced and what closed." The most common choice for content teams because it credits the discovery moment and the closing moment without either dominating.
The honest way to use these is to report several side by side rather than picking the one that flatters content most. If content looks valuable under time-decay, the model biased against it, that's a far stronger argument to finance than cherry-picking first-touch.
A word on data-driven attribution before you trust it
GA4's data-driven model uses Shapley values to distribute credit based on patterns in your conversion data, which sounds like the rigorous answer to all of the above. It's better than last-click for credit distribution. It is not a causal measure of what content is worth.
DDA is correlational. It learns which touchpoint patterns coincide with conversions in your history; it doesn't run the counterfactual of whether the conversion would have happened anyway. The gap is large. A 2026 IEEE Access study by Chivukula and colleagues at Dropbox measured click-based attribution, DDA included, against geo-incrementality experiments and found click attribution overstated causal impact by two to ten times. DDA also needs real volume, Google recommends on the order of a few hundred conversions a month before the model is stable, which puts it out of reach for many B2B properties.
Both rules-based MTA and DDA describe correlation, not causation. Neither tells you what would have happened without the touch. Keep that honesty in your back pocket, because someone in the room will eventually ask, and having pre-empted it is worth more than any model choice.
Building the MTA view in BigQuery
The GA4 BigQuery export is free to enable and unsampled, giving you every event rather than the sampled aggregate the UI shows. That's what makes custom attribution possible. Google Cloud's free tier covers 1 TiB of query and 10 GiB of storage per month, which comfortably fits most mid-sized properties.
Three schema facts save hours of confusion. The traffic_source field at the top level is user-level first-touch, not the session's source, a notorious trap. For session-level channel you want session_traffic_source_last_click, a struct Google added to the export in July 2024. And a session is identified by combining user_pseudo_id with the ga_session_id event parameter, since neither alone is unique across users.
The approach: extract sessions with their channel and start time, find each user's conversion, treat every prior session as a touchpoint on the path, then apply each model's credit rule. Credit is normalized so every conversion sums to exactly 1.0 under every model, which is the property that makes the numbers add up when you present them.
-- Lightweight multi-touch attribution from the GA4 BigQuery export.
-- Set: your export dataset, conversion event name ('purchase' here),
-- and lookback window (90 days here).
WITH events AS (
SELECT
user_pseudo_id,
CONCAT(
user_pseudo_id, '.',
CAST((SELECT value.int_value FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS STRING)
) AS session_id,
event_name,
TIMESTAMP_MICROS(event_timestamp) AS event_ts,
session_traffic_source_last_click.manual_campaign.source AS source,
session_traffic_source_last_click.manual_campaign.medium AS medium
FROM `project.analytics_XXXXXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN
FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY))
AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())
),
-- one row per session: channel + session start
sessions AS (
SELECT
session_id,
user_pseudo_id,
ANY_VALUE(source) AS source,
ANY_VALUE(medium) AS medium,
MIN(event_ts) AS session_start
FROM events
GROUP BY session_id, user_pseudo_id
),
-- first conversion per user in the window
conversions AS (
SELECT user_pseudo_id, MIN(event_ts) AS convert_ts
FROM events
WHERE event_name = 'purchase'
GROUP BY user_pseudo_id
),
-- every session before the conversion is a touchpoint on the path
touchpoints AS (
SELECT
s.user_pseudo_id, s.source, s.medium, s.session_start,
ROW_NUMBER() OVER (
PARTITION BY s.user_pseudo_id ORDER BY s.session_start) AS touch_rank,
COUNT(*) OVER (PARTITION BY s.user_pseudo_id) AS path_length,
TIMESTAMP_DIFF(c.convert_ts, s.session_start, DAY) AS days_before_convert
FROM sessions s
JOIN conversions c USING (user_pseudo_id)
WHERE s.session_start <= c.convert_ts
),
credited AS (
SELECT
source, medium, user_pseudo_id,
-- LINEAR
1.0 / path_length AS linear_credit,
-- POSITION-BASED 40/20/40
CASE
WHEN path_length = 1 THEN 1.0
WHEN touch_rank = 1 OR touch_rank = path_length THEN 0.4
ELSE 0.2 / (path_length - 2)
END AS position_credit,
-- TIME-DECAY, 7-day half-life (normalized below)
POW(2, -days_before_convert / 7.0) AS decay_weight,
-- FIRST / LAST for reference
CASE WHEN touch_rank = 1 THEN 1.0 ELSE 0 END AS first_credit,
CASE WHEN touch_rank = path_length THEN 1.0 ELSE 0 END AS last_credit
FROM touchpoints
),
-- normalize time-decay so each conversion sums to 1.0
decay_norm AS (
SELECT *,
decay_weight / SUM(decay_weight) OVER (PARTITION BY user_pseudo_id)
AS decay_credit
FROM credited
)
SELECT
source, medium,
ROUND(SUM(first_credit), 1) AS first_touch,
ROUND(SUM(last_credit), 1) AS last_touch,
ROUND(SUM(linear_credit), 1) AS linear,
ROUND(SUM(position_credit), 1) AS position_based,
ROUND(SUM(decay_credit), 1) AS time_decay
FROM decay_norm
GROUP BY source, medium
ORDER BY linear DESCRead the output as one row per channel, with five columns showing how many conversions that channel earns under each model. The story is in the spread. A channel whose last-touch number is tiny and whose first-touch and linear numbers are large is a channel last-click has been robbing. That's usually where your top-of-funnel content lives.
Making it defensible, and cheaper to run
A few refinements matter before this survives scrutiny.
The session_traffic_source_last_click struct applies last-non-direct logic at the session level, which is Google's convention, not a law. Direct sessions inherit the prior non-direct source. That's usually what you want for attribution; know it's happening.
Cost control: don't query the raw events_* export on every run. Materialize the sessions result into its own table on a schedule, then run attribution against that. Session-level tables are far cheaper to query than the event-level export, and the attribution logic doesn't need event granularity once sessions are built.
Set the lookback to your real sales cycle. Ninety days is GA4's default for most key events. A B2B cycle running longer will truncate early touches at 90 days and quietly re-credit later ones, which biases the whole thing toward the bottom of the funnel. Match the window to how people actually buy.
Bucket source and medium into channel groups (organic, paid, email, social, referral, direct) for reporting, or the output fragments across dozens of source/medium pairs. A CASE statement mirroring GA4's channel definitions does the job.
The stat to be skeptical of when you make this case
Making the content-ROI argument, you'll be tempted to reach for conversion-rate multipliers floating around the industry, claims that AI-referred or content-driven traffic converts several times better than the baseline. Handle these with care.
The numbers don't agree with each other, which is the tell. One widely cited 2026 roundup reports Similarweb putting ChatGPT-referred conversion at 11.4% against 5.3% for organic, while in the same breath citing an academic study of $20B in orders across 973 sites (Schulze and Kaiser) that found ChatGPT traffic converting 13% worse than organic. Same channel, opposite conclusions, because the studies used different attribution models, site sizes and channel maturity. Any single conversion-multiplier stat is only as good as the attribution model beneath it, which is the whole point of this post. Cite the range and the disagreement, not the flattering end.
Your own MTA table is stronger evidence than any borrowed multiplier, because it's your data, your buyers, and a model whose logic you can show line by line.
FAQ
Can I change GA4's attribution model to linear or time-decay? No. GA4 removed first-click, linear, time-decay and position-based from the interface in late 2023. Only data-driven and last-click remain selectable. To use the others you rebuild them from the BigQuery export, which is what the query above does.
What's the difference between multi-touch attribution and data-driven attribution? Multi-touch is the general idea of crediting multiple touchpoints. Rules-based MTA (linear, time-decay, position-based) uses a fixed formula you control. GA4's data-driven attribution uses machine learning to infer credit from your conversion patterns. DDA is less transparent and needs high conversion volume, but adapts to your data; rules-based is fully inspectable but arbitrary.
Does multi-touch attribution prove content caused revenue? No, and don't claim it does. Both rules-based MTA and DDA are correlational. They show content appeared on converting paths, not that conversions wouldn't have happened without it. A 2026 Dropbox study found click-based attribution overstates causal impact by two to ten times versus incrementality experiments. MTA is a much better credit story than last-click; causal proof needs controlled tests.
How do I attribute AI traffic that arrives with no referrer? You largely can't, and no model fixes it. Traffic from AI answers frequently arrives with no referrer and lands in Direct, and research-stage AI interactions that never send a click can't appear in your analytics at all. MTA improves how you credit the touches you can see; it doesn't recover the invisible ones. Treat that as a known floor on what any attribution can measure.
Do I need BigQuery, or can I do this in the GA4 UI? For anything beyond last-click and data-driven, you need the export. The UI no longer exposes the rules-based models. The BigQuery export is free to enable and unsampled, and the free Cloud tier covers most mid-sized properties.
What lookback window should I use? Match your sales cycle. GA4 defaults to 90 days for most key events. Too short and early content touches fall outside the window and lose all credit, biasing results toward bottom-funnel channels.
Which model should I show leadership? Show several. Reporting first-touch, linear, time-decay and position-based side by side is more credible than one hand-picked model. If content holds up under time-decay, which structurally underweights early touches, that's your strongest and least-attackable case.
Where RankSage fits
Everything above is reconstructable by hand: enable the export, write the SQL, schedule the table, bucket the channels, match the window to your cycle, and rebuild it when GA4's schema shifts. It works, and plenty of teams should just do it.
What it doesn't do is connect the touch credit to what people actually did on each page, or to whether your content is showing up in the AI answers that increasingly own the research stage before any session exists. RankSage is being built to join those: GA4 and Search Console data with first-party behavioural signals and AI citation data across ChatGPT, Claude, Gemini, Perplexity and Copilot, per page, so a content touch can be read alongside its citation footprint and its on-page behaviour rather than as an isolated row in an attribution table.
The honest caveat this post has earned: joining that data improves the credit story, it doesn't make it causal, and it can't attribute the AI research touches that never became a session, because nothing can. It isn't launched yet. If you're building this case for your own leadership now, join the waitlist for early access.
