The Muddy embed sends an event to your page whenever a customer confirms, reschedules or cancels a booking. You can listen for these and pass them on to Google Analytics, Google Tag Manager, Meta Pixel or any other analytics tool.
If the Muddy embed snippet is on the page, the events are already firing. All you need to add is a listener.
Which events to listen for
Add listeners to window, not the iframe or the message event. The full payloads are in the Embed JavaScript API reference.
muddy.booking:confirmedfires once, on the confirmation page after a booking. Use this for conversion tracking.muddy.booking:rescheduledfires when a booking is rescheduled or edited.muddy.booking:cancelledfires as soon as a customer cancels a booking.
Minimal example
Add this to your page to check the events are arriving:
window.addEventListener('muddy.booking:confirmed', function (event) { console.log('Booking confirmed', event.detail); });
Open your browser console and make a test booking through the embed. The payload is logged when you reach the confirmation page.
Google Analytics 4 (gtag.js)
This sends a GA4 purchase event on confirmation, a refund event on cancellation and a custom event on reschedule.
window.addEventListener('muddy.booking:confirmed', function (event) { var d = event.detail; gtag('event', 'purchase', { transaction_id: d.reference, value: Number(d.price.total.amount), currency: d.price.total.currency, items: [{ item_id: String(d.slot.has_slots.id), item_name: d.slot.has_slots.label, item_category: d.slot.has_slots.type, price: Number(d.price.total.amount), quantity: 1 }] }); }); window.addEventListener('muddy.booking:cancelled', function (event) { var d = event.detail; gtag('event', 'refund', { transaction_id: d.reference, value: Number(d.price.total.amount), currency: d.price.total.currency }); }); window.addEventListener('muddy.booking:rescheduled', function (event) { var d = event.detail; gtag('event', 'booking_rescheduled', { transaction_id: d.reference, item_name: d.slot.has_slots.label, new_start: d.slot.start.iso }); });
Google Tag Manager (dataLayer)
Push each event onto the dataLayer and let GTM send it on to GA4, Meta Ads or anywhere else.
window.dataLayer = window.dataLayer || []; ['confirmed', 'rescheduled', 'cancelled'].forEach(function (state) { window.addEventListener('muddy.booking:' + state, function (event) { var d = event.detail; window.dataLayer.push({ event: 'muddy_booking_' + state, muddy: { booking_id: d.id, booking_reference: d.reference, value: Number(d.price.total.amount), currency: d.price.total.currency, walk_id: d.slot.has_slots.id, walk_name: d.slot.has_slots.label, slot_start: d.slot.start.iso } }); }); });
Setting up the GTM triggers
- In GTM, create a Custom Event trigger. Set the event name to
muddy_booking_confirmed. Repeat formuddy_booking_rescheduledandmuddy_booking_cancelled. - Create Data Layer Variables for the fields you need, for example
muddy.booking_reference,muddy.value,muddy.currencyandmuddy.walk_name. - Use those variables in a GA4 Event tag, or any other tag, and set its trigger to the Custom Event from step 1.
Meta / Facebook Pixel
window.addEventListener('muddy.booking:confirmed', function (event) { var d = event.detail; fbq('track', 'Purchase', { value: Number(d.price.total.amount), currency: d.price.total.currency, content_ids: [String(d.slot.has_slots.id)], content_name: d.slot.has_slots.label, content_type: 'product' }); });
Forwarding to any analytics SDK
PostHog, Segment, Mixpanel, Amplitude and your own endpoints all work the same way: read event.detail, pick the fields you want, and call your SDK's tracking method.
window.addEventListener('muddy.booking:confirmed', function (event) { var d = event.detail; analytics.track('Booking Confirmed', { booking_reference: d.reference, value: Number(d.price.total.amount), currency: d.price.total.currency, walk_name: d.slot.has_slots.label, slot_start: d.slot.start.iso }); });
Troubleshooting
The value sent to analytics is a string or NaN. amount is a decimal string like "25.00". Wrap it in Number(...) before passing it to GA4, Meta Pixel and so on, or use amount_minor if your tool wants minor units.
The event fires twice. You may be adding the listener in code that runs on every route change of a single-page app. Add it once, at page load.
For other problems, such as nothing firing, event.detail being undefined or missing customer data, see Troubleshooting in the Embed JavaScript API reference.