When guests book through the embedded widget on your website (e.g., yourdomain.com), they pass through a payment gateway and land on your Understory storefront (e.g., yourcompany.understory.io) for the receipt. Because these are different domains, Google Analytics treats them as separate visits — meaning you can't attribute completed bookings back to your marketing efforts.
Understory solves this by automatically bridging the analytics session between your website and your storefront. Depending on your tracking setup, this may work automatically or require a small one-time configuration in Google Tag Manager.
What Understory does automatically
When a guest starts the booking flow from your embedded widget, Understory captures their Google Analytics session data (client ID and session ID) from your website. This data is carried through the payment process and made available on your storefront via the dataLayer.
Specifically, Understory pushes a session_bridge event to the dataLayer with two values:
ga_client_id— the GA4 client identifier from your websitega_session_id— the GA4 session identifier from your website
You don't need to do anything to enable this — it happens automatically.
Setup depends on your tracking configuration
Option A: You use Understory's built-in GA4 integration
If you added your GA4 Measurement ID in Growth > Tracking and do not use your own GTM container, session bridging works automatically. Understory's GTM container reads the bridged session data and configures GA4 with the correct client ID and session ID.
You still need to configure cross-domain measurement in GA4 (Step 1 below) so that GA4 recognizes your website and storefront as related domains.
Option B: You use your own GTM container
If you enabled your own GTM container (see Using Your Own Google Tag Manager Container), you need to configure your GA4 tag to read the bridged session data. Follow all steps below.
Option C: You imported the Understory GTM template
If you imported the Understory GTM storefront template after March 2026, the session bridge variables are already included. Just make sure you've configured cross-domain measurement in GA4 (Step 1 below).
How to set up cross-domain conversion tracking
Step 1: Configure cross-domain measurement in GA4
Required for all setups. This tells Google Analytics that your website and your Understory storefront belong together.
Open Google Analytics — go to Admin at the bottom of the left menu
Select Data Streams — then click on your web stream
Click "Configure tag settings" — then select Cross-domain measurement
Add your storefront domain — enter
yourcompany.understory.io(replace with your actual storefront domain)Save — cross-domain measurement is now active
If you use Understory's built-in GA4 integration (Option A), you're done. The remaining steps are only for customers using their own GTM container.
Step 2: Create Data Layer Variables in GTM
These variables let your GA4 tag read the session data that Understory passes on the receipt page.
Open Google Tag Manager — go to Variables in the left menu
Click New — under "User-Defined Variables"
Choose "Data Layer Variable" as the variable type
Set the variable name to
DLV - ga_client_id— and set Data Layer Variable Name toga_client_idSave — then repeat the process for a second variable
Create another Data Layer Variable — name it
DLV - ga_session_idwith Data Layer Variable Name set toga_session_idSave — you now have both variables ready
Step 3: Create fallback variables for safe field overrides
You need variables that return the bridged value when available, and fall back to the automatic GA4 value when it's not. This prevents duplicate tracking.
Go to Variables — click New under "User-Defined Variables"
Choose "Custom JavaScript" as the variable type
Name it
CJS - Client ID Override— and enter this code:
function() {
var val = ##{{DLV - ga_client_id}};
return val ? val : undefined;
}
Save — then create a second Custom JavaScript variable
Name it
CJS - Session ID Override— and enter this code:
function() {
var val = ##{{DLV - ga_session_id}};
return val ? val : undefined;
}
Save — these variables return
undefinedwhen no bridged data is available, which tells GA4 to use its default values
Step 4: Add session bridging to your existing Google Tag
Important: Do not create a separate Google Tag for this. Modify your existing Google Tag to avoid duplicate events.
Open your existing Google Tag — the one that fires on All Pages with your GA4 Measurement ID
Expand "Configuration settings" — then click Fields to set
Add two fields:
Field Name:
client_id— Value:##{{CJS - Client ID Override}}Field Name:
session_id— Value:##{{CJS - Session ID Override}}
Save the tag
When a guest arrives from your widget, these fields use the bridged values from your website. For all other visits, the values are undefined and GA4 uses its default behavior. This means your purchase event fires exactly once with the correct session — no duplicates.
Technical background: Setting client_id and session_id via Fields to Set is the documented GA4 approach for manual cross-domain measurement. It's the same mechanism as the automatic _gl linker parameter, but works reliably across payment gateway redirects where the linker parameter would expire.
How to test your setup
Enable GTM Preview mode — click Preview in the top right of your GTM workspace
Complete a test booking — go through the full booking flow using your embedded widget on your website
Check the GTM Preview panel on your storefront — verify that the
session_bridgeevent fires and that thega_client_idvalue matches the one from your websiteVerify your Google Tag — in the Preview panel, click on your Google Tag and confirm that
client_idshows the bridged value (not a new auto-generated one)Open GA4 DebugView — go to Admin then DebugView in Google Analytics. Confirm that events from both your website and storefront show the same
client_id, and that thepurchaseevent appears in the same session as the widget interactionsCheck for duplicates — make sure the
purchaseevent only appears once per booking in GA4
Troubleshooting
Purchases showing as "organic shopping" or wrong source in GA4? This happens when the purchase event fires in a disconnected session on the storefront. Make sure cross-domain measurement is configured (Step 1), and if you use your own GTM container, verify that the session bridging fields are set on your Google Tag (Steps 2–4).
No session_bridge event on the storefront? Make sure your website has GA4 running and creating cookies. The embedded widget reads the _ga cookie to capture the client ID. If GA4 isn't loaded on your website, there's nothing for the widget to capture.
ga_client_id is empty? Check that your GA4 tag fires before the embedded widget renders on your website. If GA4 loads after the widget, the cookies may not be set yet.
Sessions still appear separate in GA4? Verify that cross-domain measurement (Step 1) includes your storefront domain. Also confirm that the client_id field override in your Google Tag (Step 4) is correctly configured and that the Custom JavaScript variables (Step 3) return the right values.
Duplicate purchase events? Make sure you modified your existing Google Tag in Step 4 rather than creating a new one. Having two Google Tags with the same Measurement ID will cause duplicate events.
Using a cookie consent banner? If you use a consent management tool, GA4 cookies may not be set until the guest gives consent. The widget can only capture the client ID if the _ga cookie exists. Guests who decline analytics cookies won't have their sessions bridged.
Did this answer your question? If not, please reach out to us in the chat window at the bottom to the right, and we'll be happy to help.
