Repository navigation
Head hook and GA4 checkout step events - #5
alecritson wants to merge 3 commits into
Conversation
The checkout renders its own document, so a store had no way to add Tag Manager to it, and the steps between begin_checkout and purchase sent nothing. - lunar-checkout::partials.head: an empty include at the end of the head, overridable from resources/views/vendor/lunar-checkout/. - add_shipping_info (shipping_tier) when a delivery method or collection is chosen, or at pay if the server chose it; add_payment_info (payment_type) when the customer pays. Each once per tier/method. - Events go to window.dataLayer only when the host created one, so no Tag Manager or no consent means nothing is sent. - node:test coverage for the event helper (npm test, run in CI). Refs KJS-209 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A store's "Checkout" or "Buy Now" request ends in Inertia::location, a full page visit, so its onSuccess never runs and it can't tell the checkout started. Send begin_checkout from the checkout on first load instead, once per session per tab (sessionStorage), so every way in is counted once and only when the checkout really started. Refs KJS-209 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Added in 1d9bf9c: the checkout now sends |
TheAaronLawrence
left a comment
There was a problem hiding this comment.
I've left 2 comments: begin_checkout now also fired here; may duplicate storefront's event; payment_type uses the display label, which may be localized or vary.
Additional findings
-
payment_type uses the display label, which may be localized or vary (
resources/js/composables/useCheckout.js:349) · Low · Quick checktrackPaymentusesmethod.label ?? method.handleaspayment_type. Labels are display text that can change with locale or configuration, which fragments GA4 reports and makes the dedupe key unstable. Prefer the stablehandle, or send the handle as the value and keep the label out of it.
| state.method = state.paymentMethods[0]?.handle ?? null | ||
|
|
||
| // GA4 begin_checkout for a host running Tag Manager, once per session. | ||
| trackCheckoutStart(data.uuid, { items: state.items, currency: state.currency }) |
There was a problem hiding this comment.
begin_checkout now also fired here; may duplicate storefront's event
Medium · Quick check
The PR description and KJS-209 say begin_checkout is already sent by the storefront (KJS-97, basket and Buy Now). This PR adds trackCheckoutStart, which fires begin_checkout again on checkout load. The README even says the store should not send its own. If the storefront still sends it, GA4 will count two begin_checkout events per checkout and distort funnel numbers. The change is also missing from the PR description's change list.
Suggested fix: either remove it from the package, or confirm that KJS-97's event is removed in KJP and document this in the PR. The sessionStorage dedupe only protects against reloads within this app. It doesn't protect against the storefront's event.
There was a problem hiding this comment.
No double count: KJP already stopped sending its own begin_checkout in neondigital/kjpspares.co.uk@c44afc6d (useAddToCart.test.ts checks it stays out). The checkout owns the event now. I've added it to the PR description's change list.
The display label can change with locale or config, which splits GA4 reports and the once-per-method dedupe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
payment_type: fixed in 24e66a0. It now sends the payment method handle ( |
The checkout renders its own document (
lunar-checkout::app), so a store had no way to add Tag Manager to it, and the only checkout event waspurchase(confirmation). A store's Checkout or Buy Now request ends inInertia::location, so the store can't reliably sendbegin_checkouteither.Changes
lunar-checkout::partials.head, an empty include at the end of<head>. A store overrides it fromresources/views/vendor/lunar-checkout/partials/head.blade.php.window.dataLayer, withcurrency,valueanditems:begin_checkouton first load of the checkout, once per session per tab (tracked insessionStorage). The store must not send its own; KJP removed its one in kjpspares.co.ukc44afc6d.add_shipping_infowithshipping_tier, when a delivery method or collection is chosen. If the server chose it, it is sent at pay instead.add_payment_infowithpayment_type(the payment method handle, e.g.card), when the customer pays.window.dataLayerexists. The host creates it in the head hook once the shopper has consented.npm test(node:test, no new dependencies) covers the event helper and runs in the existing vite build job. There are two feature tests for the head hook.resources/dist.Test plan
vendor/bin/pest --testsuite checkout(317 passed)npm testbegin_checkout,add_shipping_info,add_payment_info,purchase. With cookies rejected, nothing goes to googletagmanager.com.Refs KJS-209
🤖 Generated with Claude Code