Littledata MonitorAI guide

UPLOAD_CLICKS conversion actions do not receive view-through attribution

Investigation date: 2026-05-21 Trigger: The conversion-window experiment for Tentbox UK widened the Littledata purchase action’s view-through window from 1 day to 30 days and found no significant increase in attributed conversions, despite the account running a Demand Gen campaign with 494k impressions in the last 30 days. This document captures the underlying reason and the cross-account evidence.


Headline

Qualification added 2026-08-28. Every number in this document is metrics.view_through_conversions, which counts only IMPRESSION-attributed conversions and silently omits ENGAGED_VIEW — a 10s+ view of a skippable video ad, and where Performance Max and Demand Gen book most of their impression-side credit. So “zero view-through” below means zero IMPRESSION credit, which is still the structural finding. It is not zero impression-side credit: read against segments.conversion_attribution_event_type, UPLOAD_CLICKS actions do take a small non-zero amount of engaged-view credit — 4.3 conversions / $268 on becausemarket-prod over 14 days, against 35.9 / $2,596 on the WEBPAGE action in the same account and window. The asymmetry between the two action types holds; its size is understated here. See Littledata Google Ads purchase connection: v1 vs v2, measured.

Across five Littledata customers — including ones running heavy Demand Gen / YouTube spend — every UPLOAD_CLICKS-type conversion action receives zero view-through conversions, while WEBPAGE-type actions on the same shops, on the same campaigns, capture meaningful VTC volume. The pattern is structural and is consistent with Google’s documented attribution architecture: UPLOAD_CLICKS, by definition, ties a conversion to a specific click ID and has no impression-side attribution pathway. Enhanced-conversion fields (hashed email, phone, address) sent on UPLOAD_CLICKS uploads improve click matching; they do not unlock view-through credit. This is why widening the LD action’s view-through window has no effect on reported conversions.


Evidence — VTC by conversion action, by shop, last 30 days

All numbers from googleAds:search GAQL queries, segmented by segments.conversion_action, using metrics.view_through_conversions and metrics.all_conversions (the latter so secondary actions are included).

1. gurneys-seeds — the controlled comparison

Demand Gen / Video surface only, last 30 days. Same shop, same campaigns; only the conversion action type changes. This is the cleanest evidence of the structural pattern.

Conversion action Type Primary Conv VTC VTC %
Purchase/Sale WEBPAGE 119 9 7.5%
Add to Cart WEBPAGE 1 246 78 6.3%
Email Sign Up WEBPAGE 2 283 82 3.6%
Google Shopping App Add To Cart WEBPAGE 4 500 82 1.8%
Google Shopping App Page View WEBPAGE 141 651 1 953 1.4%
Purchase - Littledata UPLOAD_CLICKS 92 0 0.0%
YouTube follow-on views UNKNOWN 119 0 0.0%
GU-GA4-Default ZoneFinder_submitted GOOGLE_ANALYTICS_4_CUSTOM 9 0 0.0%

The primary purchase action (Purchase/Sale, WEBPAGE pixel) captures 9 view-throughs on 119 Demand Gen conversions — a 7.5% VTC share. The Littledata UPLOAD_CLICKS purchase action, on the same Demand Gen campaign with comparable conversion volume (92), captures 0 VTCs. GA4-source and “UNKNOWN” (YouTube-engagement) actions also receive zero.

2. tentbox-6623 (UK) — the originating case

Demand Gen Remarketing 2026 campaign, last 30 days. 494k impressions.

Conversion action Type Conv VTC VTC %
Add to basket - Shopify WEBPAGE 199 40 20.1%
Purchase Shopify Test WEBPAGE (primary, inMetric) 27 7 25.5%
Purchase - Littledata UPLOAD_CLICKS 13 0 0.0%
New Customer Purchase - Littledata UPLOAD_CLICKS 5 0 0.0%
Returning Customer Purchase - Littledata UPLOAD_CLICKS 7 0 0.0%
TentBox - GA4 (web) session_start GOOGLE_ANALYTICS_4_CUSTOM 2 385 0 0.0%
Purchase - GA4 GOOGLE_ANALYTICS_4_PURCHASE 2 0 0.0%
YouTube follow-on views UNKNOWN 4 119 0 0.0%

The pixel-based primary purchase action gets a 25.5% VTC share from Demand Gen. The three Littledata UPLOAD_CLICKS actions get 0% — combined, they would have to capture roughly 6–7 VTCs to match the WEBPAGE rate. They capture zero.

3. todd-snyder — large account, no Demand Gen, same pattern

No Demand Gen activity in the last 30 days, but across Shopping / Search / PMax the asymmetry is identical at scale:

Conversion action Type Conv VTC
Google Shopping App Page View WEBPAGE 1 659 168 2 191
Google Shopping App View Item WEBPAGE 1 002 228 1 182
Google Shopping App Purchase WEBPAGE 8 155 7
CHEQ for PPC - Invalid Users WEBPAGE 5 534 30
Purchase - Littledata UPLOAD_CLICKS 5 523 0
Returning Customer Purchase - Littledata UPLOAD_CLICKS 3 216 0
New Customer Purchase - Littledata UPLOAD_CLICKS 2 234 0
Todd Snyder - GA4 (web) purchase GOOGLE_ANALYTICS_4_PURCHASE 1 236 0

Every WEBPAGE action records VTCs. Every UPLOAD_CLICKS and GA4-import action records zero.

4. wink-beds-2-0 — same pattern at the high-AOV mattress vertical

Conversion action Type Conv VTC
Google Shopping App Page View WEBPAGE 75 649 10
Shopify Purchase WEBPAGE 844 0
Purchase - Littledata UPLOAD_CLICKS 760 0
New Customer Purchase - Littledata UPLOAD_CLICKS 584 0
Returning Customer Purchase - Littledata UPLOAD_CLICKS 179 0
_Winkbeds.com - GA4 (web) purchase GOOGLE_ANALYTICS_4_PURCHASE 1 253 0

(Wink-beds has low absolute VTC volume across all actions — but the only action that records any VTC is WEBPAGE. UPLOAD_CLICKS and GA4-import again record zero.)

5. roseland-furniture — the cautionary case

Demand Gen / Video surface, last 30 days. This account has no WEBPAGE-type primary purchase action — its entire conversion stack is UPLOAD_CLICKS plus GA4 imports.

Conversion action Type Primary Conv VTC
ThoughtMetric Attributed Sale UPLOAD_CLICKS 125 0
Purchase - Littledata UPLOAD_CLICKS 84 0
roseland-furniture - LD Property (web) purchase GOOGLE_ANALYTICS_4_PURCHASE 48 0
Roseland Furniture - GA4 (web) purchase_2 GOOGLE_ANALYTICS_4_CUSTOM 30 0
YouTube follow-on views UNKNOWN 54 0

Total Demand Gen VTC for this shop: 0. A shop running Demand Gen with no WEBPAGE conversion action captures zero view-through credit for that spend — regardless of enhanced conversions. The video-surface spend is producing impressions that no conversion action in the account is able to attribute to.


Why this happens — the API-level mechanism

UPLOAD_CLICKS and WEBPAGE are two fundamentally different conversion-source types in the Google Ads API. The view-through pathway only exists in one of them.

WEBPAGE (pixel/tag-based): A Google Ads Tag fires in the user’s browser at conversion time. Google’s servers receive the event with the user’s Google cookies and any enhanced-conversion fields the tag sends. Google can then match the conversion to any prior touchpoint Google has on that user — clicks and impressions, via the identity graph. View-through attribution is generated server-side after the fact, comparing the conversion event to all impressions served to that identity within the action’s view-through window.

UPLOAD_CLICKS (offline/server-side click attribution): The advertiser uploads, via the API, a conversion event annotated with a gclid (Google click identifier). The API contract is, literally, “this conversion belongs to this click.” The impression that led to that click is captured implicitly through the click record, but impressions that did not produce a click are not part of the upload’s attribution surface. There is no GAQL field, no API parameter, and no documented mechanism by which an UPLOAD_CLICKS upload can be matched to a view-only impression.

Enhanced-conversion fields (hashed email/phone/address) attached to an UPLOAD_CLICKS upload do real, useful work — but the work they do is improving the match for the click side of the upload: recovering a gclid when one was missing, deduplicating against parallel WEBPAGE conversions, or upgrading the credit on a click that was already attributed. They do not create a new view-through credit, because the upload was never tied to an impression record in the first place.

This is confirmed in the data across five accounts above:

The conversion-window experiment widens VT on the LD UPLOAD_CLICKS action. Widening a window that already attributes only clicks cannot increase VTC — there are no view-throughs in the data path to capture. The experiment is not “failing to find uplift”; it is structurally measuring something that cannot move.


Implications

  1. For Tentbox specifically: the view-through value of their Demand Gen spend is being captured by the Purchase Shopify Test WEBPAGE action (25.5% VTC share on Demand Gen) — that’s the action that should be examined when evaluating Demand Gen ROAS. Littledata’s UPLOAD_CLICKS action will continue to show zero VTCs on Demand Gen regardless of any window setting.
  2. For Littledata as a product: customers running heavy YouTube / Demand Gen spend, whose conversion stack is only UPLOAD_CLICKS or GA4 imports (e.g. Roseland), are losing the view-through component of their attribution entirely. The remedy is a WEBPAGE-type conversion action with enhanced conversions enabled at the Tag level — not a wider VT window on the upload action.
  3. For the conversion-window experiment framework: the metric it measures (impact of widening VT on UPLOAD_CLICKS attribution) is structurally bounded near zero. The framework should still be useful for measuring CT-window changes, where UPLOAD_CLICKS genuinely does attribute, but VT-window changes on UPLOAD_CLICKS are expected null results and should probably not be flagged as success unless the captured ratio is materially above 1.0.

Resolution (2026-05-23)

Implication #3 is now reflected in the code (src/services/googleAds/captureLittledataAtPrimaryLookback.ts):

The 6/12/24h inconclusive_retry ladder is also gone: across ~40 captured experiments, CT reattribution plateaued by ~12h with sub-0.5% movement at 24h. Replaced by a single 24h finalize (FINALIZE_WAIT_HOURS = 24). Legacy inconclusive_retry docs in-flight at deploy time are tolerated and finalized terminally on their next cron pass.


Reproduction

Data above can be regenerated for any shop with:

cd monitoring-ai
npx tsx scripts/dump-ld-vtcs-by-campaign.ts <shopName> [days=30]

Schema: GAQL SELECT campaign.id, campaign.name, campaign.advertising_channel_type, segments.conversion_action, metrics.all_conversions, metrics.all_conversions_value, metrics.view_through_conversions FROM campaign WHERE segments.date BETWEEN <start> AND <end>, filtered post-fetch to the action(s) named Purchase - Littledata (constant LD_PURCHASE_ACTION_PREFIX in src/services/googleAds/constants.ts).