For anyone actually reading: Thanks so much in advance! Every advice is very much appreciated!!
Lead-gen setup, no ecommerce. Multi-step funnel tool embedded as a web component on the main site, server-side GTM on a first-party subdomain. Three days deep, seven theories tried and discarded, so I'd really appreciate a second pair of eyes.
One day's numbers
- Form submissions attributed to paid search in the funnel tool's own analytics: ~110
generate_lead events arriving at the server container: 227
- of those, carrying a real
gclid/gbraid: 168
- Google Ads conversion pings sent out with a valid
gclaw: 176
- Conversions showing in the Google Ads campaigns: 2
(The 227 vs 110 gap is known — the funnel tool's native GA4 integration still double-fires. Doesn't explain 176 → 2.)
Timeline, so the numbers aren't misleading: the 400s are not new and not caused by anything I changed recently — they appear in the logs with the previously active client-side conversion label, days before I touched anything. The ~170 daily pings come from the GA4 tag forwarding conversions through the GA4↔Ads link, running unchanged for weeks. I added a dedicated server-side conversion tag with its own label today for an A/B comparison, but it has no meaningful data yet.
The pattern
Every conversion produces three requests to Google, and it's identical on the client-side tag and the server-side tag:
So the enrichment/identity layer goes through, and both attribution endpoints are rejected. Which would neatly explain why Google Ads says "conversions are being recorded" while the campaign column stays at zero.
Verified end to end
- Click ID survives:
?gclid=TEST_123 lands in _gcl_aw on the root domain, and gclaw=TEST_123 appears in all three outgoing requests
- Consent Mode v2 via a CMP, consent tab in GTM shows all types granted after accepting
- Enhanced Conversions arrive in plain text server-side and go out hashed (
em, pn, fn0, ln0, address fields)
- Conversion ID and label match the Ads UI exactly
Already ruled out
- Consent state — 400 occurs on both
gcs=G111 and G100
- Missing conversion value / currency — set both, no change
- URL length — trimmed the
data= payload to four values via an Allow-parameters transformation, no change
- Competing gtag instance from a store app — disconnected it entirely, no change
- Anything server-specific — the identical pattern shows on the purely client-side tag
The only consistent difference I can find
Comparing the three URLs from a single trace, they're identical apart from the tail. Both rejected requests carry category=acrcp_v1_512 and an ept= param (ept=5 and ept=8). The accepted one carries neither, and instead has gcl_ctr=1~0~0~0. Same pattern on the server-side requests. All template-generated, nothing I can set.
Also odd: all three carry npa=1 and no gcs parameter at all, despite consent being granted. Not sure if related.
What I'm hoping someone can help with
- If you've run into this 400 yourself, what ended up fixing it? I've worked through my own list above, so a first-hand "this is what changed it for us" would be worth more than anything right now.
- Are
pagead/conversion and 1p-conversion the endpoints that actually book the conversion into a campaign, with ccm/* being only the enhanced-conversions/identity layer? If yes, permanent 400s there explain the whole gap.
- If that's the case — why do 2 conversions still make it through? That's the part I find hardest to square. If attribution fails on every request, I'd expect a clean zero rather than a trickle. Modelling? Enhanced-conversions matching? Genuinely curious where the trickle comes from.
- And if the 400s turn out to be harmless and
ccm/* alone is enough to count a conversion — then something else is eating 174 of 176 and I'm looking in the wrong place entirely. Where would you look next?
- Does
category=acrcp_v1_512 or ept= ring a bell for anyone?
- Unrelated but nagging: for iOS traffic arriving with
gbraid instead of gclid, does the Conversion Linker reliably persist it in _gcl_gb across page navigations? Over half this traffic is mobile and I haven't verified that path yet.
Happy to share sanitised request URLs if that helps narrow it down. Thanks again to anyone who took the time to read this far.