Online booking software is one of the best things a transportation business can add, and one of the worst things for tracking. The customer clicks your ad, lands on your site, opens the reservation form and books a trip. Then Google Ads reports nothing, GA4 shows the visit ending on your "Book now" page, and Meta Ads has no idea anything happened. The booking is real, but your ad platforms cannot see it.
This guide explains why that happens and the methods I use to fix it, from the simplest redirect to server-side conversions with deduplication.
Why don't booking engine conversions show up in GA4 and Google Ads?
Booking engine conversions often do not show up because the booking completes somewhere your tags cannot see: on another domain, inside an iframe, or in a confirmation step that never loads your Google tag. Your website tracking only works on pages where your tags run.
There are two common setups:
- Hosted booking pages. The "Book now" button sends people to a page on the vendor's domain, such as a subdomain of the booking software company. Your GTM container usually is not installed there.
- Embedded booking widgets. The booking form appears on your site but loads inside an iframe from the vendor's domain. The page looks like yours, but the iframe is a separate document, and your GTM container cannot see clicks or confirmations inside it.
Reservation systems such as Limo Anywhere and many other transportation booking tools are common in this industry. What each one allows, such as custom scripts, thank-you redirects or webhooks, varies by vendor and plan, so always check your software's documentation or ask its support team before choosing a method.
Which tracking method should you use?
The right method depends on what your booking software lets you control. Start with the simplest option that works, and add server-side tracking when you need more reliability.
| Method | When it works | Effort | Main limitation |
|---|---|---|---|
| Thank-you page redirect | Software can redirect to your own URL after booking | Low | Value and booking ID may not be passed |
| Cross-domain tracking | Booking pages are on another domain where you can add your tags | Medium | Needs your tag on the vendor's pages |
| Iframe postMessage listener | Embedded widget sends messages to the parent page | Medium | Vendor must send the messages, or let you add code |
| Webhook or server-side | Software can send booking data to a URL or CRM | Higher | Needs a server container or automation tool |
How does a thank-you page redirect work?
A thank-you page redirect works by sending the customer from the booking software to a confirmation page on your own website after they book, where your normal tags fire. It is the easiest fix when the software supports a custom redirect URL.
Set up a page such as /booking-confirmed/, make sure it is not indexed or linked from your navigation, and trigger your GA4 event and Google Ads conversion on that page in GTM. If the software can append the booking reference and total to the URL, capture them as variables so you can pass a transaction ID and value. The transaction ID lets Google Ads ignore duplicates if someone reloads the page.
How do you set up cross-domain tracking?
You set up cross-domain tracking by telling GA4 that your site and the booking domain belong to the same journey, so the user's session continues across both. Without it, GA4 can treat the booking as a new visit, often attributed to your own site as a referral.
The steps:
- In GA4, go to Admin, Data streams, select your web stream and open Configure tag settings, then Configure your domains.
- Add your website domain and the booking domain.
- Install the same Google tag or GTM container on the booking pages, if the vendor allows it.
- Add the Conversion Linker tag in GTM so Google Ads click data carries across.
- Test by clicking from your site to the booking page and checking for the
_glparameter in the URL and continuous sessions in GA4 DebugView.
If you cannot add your tags to the vendor's pages at all, cross-domain tracking will not help, and you need one of the other methods.
How does the iframe postMessage approach work?
The postMessage approach works by having the booking widget inside the iframe send a message to your page when a booking completes, which a listener on your page turns into a dataLayer event. postMessage is a standard browser feature that lets an iframe and its parent page communicate safely across domains.
This only works if the vendor sends such messages, or lets you add your own script inside the widget. When it does, a listener in a Custom HTML tag in GTM can look like this:
<script>
window.addEventListener('message', function (event) {
// Only accept messages from your booking vendor's domain
if (event.origin !== 'https://booking.example-vendor.com') return;
var data = event.data || {};
if (data.type === 'booking_complete') {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'booking_complete',
booking_id: data.bookingId,
value: data.total,
currency: data.currency
});
}
});
</script>
The domain and message format above are placeholders; the real ones come from your vendor. Always check event.origin, so other sites cannot send fake booking events. Then create a Custom Event trigger for booking_complete and fire your GA4, Google Ads and Meta Pixel tags from it.
When should you use webhooks and server-side conversions?
You should use webhooks and server-side conversions when browser-based tracking is unreliable, when the booking is confirmed later, or when you want the most complete data. A webhook is an automatic message the booking software sends to a URL when something happens, such as a new reservation.
A typical server-side flow:
- The booking software sends a webhook with booking details to a server-side GTM container or an automation tool such as Zapier or Make.
- The flow sends the booking to GA4 through the Measurement Protocol, to Google Ads as an offline or enhanced conversion, and to Meta through the Conversion API (CAPI).
- For attribution to work, the booking needs identifiers from the original visit: the GA4 client ID, the Google Ads click ID (GCLID) and the Meta click ID (fbclid stored as the
_fbccookie value). Pass them into the booking form as hidden fields or URL parameters if the software allows it.
Without those identifiers, a server-side conversion is still recorded but may not be credited to the right campaign. Hashed email and phone number help Google and Meta match more bookings. I explain the background in server-side tracking explained and the CRM side in offline conversion tracking.
How do you avoid counting the same booking twice?
You avoid double-counting by using one shared booking ID across every place the booking is sent, and by choosing one primary source per platform. Duplicates are the most common problem once both browser and server tracking are running.
A quick checklist:
- Meta: send the same
event_idand event name from the Pixel and the Conversion API so Meta deduplicates them. See my guide to Meta CAPI event deduplication. - Google Ads: pass the booking ID as the transaction ID, and do not set both the Google Ads tag conversion and an imported GA4 key event as primary for the same booking.
- GA4: fire the booking event once, either from the browser or via Measurement Protocol, not both, unless you deliberately deduplicate.
- Redirect pages: stop reloads from refiring by relying on the transaction ID.
- Test a real booking end to end and confirm one conversion per platform.
Final thoughts
Booking software does not have to be a tracking black hole. Find out what your vendor supports, start with a redirect or cross-domain setup where possible, and add webhook-based server-side conversions with shared booking IDs when you need reliable data. If you want help with your setup, my advanced conversion tracking service covers it, and you can book a free tracking audit.



