Tracking

GTM, GA4 and ad conversions

Track Microsoft Bookings conversions with Google Tag Manager, GA4, Google Ads enhanced conversions, Meta Pixel and LinkedIn, plus a thank-you redirect.

Bookings made inside Microsoft's own booking page are invisible to your analytics. With BookingsXP, the loader on your page receives each step of the booking from the widget and passes it to the tools you already run. You do not need to add code for any of this; you only need the tags on your page and, for GA4 and ad platforms, the IDs in your widget's Tracking tab.

DestinationWhat firesPlan
dataLayer (Google Tag Manager)Every event as bookingsxp.<name>Free, also in link-only mode
GA4 via gtagbookingsxp_view, bookingsxp_slot, bookingsxp_form_start, generate_lead, bookingsxp_bookedFree
Thank-you page redirectNavigates after booking_completedFree
Google Adsconversion with the booking reference as transaction_idPro
Google Ads enhanced conversionsSHA-256 of the email, hashed in the browserPro
Meta PixelSchedule on booking, ViewContent on viewPro
LinkedIn Insight TagConversion on bookingPro

The loader never loads these vendor tags itself. It calls gtag, fbq or lintrk only if the function already exists on the page and the matching ID is set on the widget. That keeps your consent tool in charge: if it has not loaded a tag, nothing is sent to that vendor. The one exception is the hosted booking page, which loads the tags for the IDs you configured because there is no host page to do it.

Google Tag Manager#

For every event, the loader pushes:

JavaScript
window.dataLayer.push({
  event: "bookingsxp.booking_completed",
  bookingsxp: {
    name: "booking_completed",
    widgetId: "w_8fk2m1qz",
    businessName: "Contoso Physio",
    service: { id: "a1b2c3", name: "Initial consultation", durationMinutes: 45, price: 60, currency: "GBP" },
    staff: { id: "d4e5f6", name: "Sam Lee" },
    slot: { start: "2026-10-02T14:00:00Z", end: "2026-10-02T14:45:00Z", timeZone: "Europe/London" },
    booking: { id: "BXP-7K3M9Q" },
  },
});

The object is the event without its tracking block. Event names are bookingsxp.widget_viewed, bookingsxp.service_selected, bookingsxp.staff_selected, bookingsxp.date_selected, bookingsxp.slot_selected, bookingsxp.form_started, bookingsxp.booking_submitted, bookingsxp.booking_completed, bookingsxp.booking_failed and bookingsxp.no_availability.

Set up a booking trigger#

  1. In GTM, go to Triggers → New → Custom Event.
  2. Event name: bookingsxp.booking_completed.
  3. Save it as "BookingsXP booking".

To catch every step instead, use the event name ^bookingsxp\. and tick Use regex matching.

Data Layer Variables#

Create these under Variables → New → Data Layer Variable (Data Layer Version 2):

Variable nameData Layer Variable Name
BXP referencebookingsxp.booking.id
BXP servicebookingsxp.service.name
BXP valuebookingsxp.service.price
BXP currencybookingsxp.service.currency
BXP startbookingsxp.slot.start
BXP staffbookingsxp.staff.name
BXP widgetbookingsxp.widgetId
BXP errorbookingsxp.error.code

Price and currency are present when the service has a price in Microsoft Bookings.

Example: a GA4 event tag in GTM#

  • Tag type: Google Analytics: GA4 Event
  • Event name: generate_lead
  • Event parameters: service_name = {{BXP service}}, value = {{BXP value}}, currency = {{BXP currency}}, transaction_id = {{BXP reference}}
  • Trigger: "BookingsXP booking"

If you do this in GTM, leave the GA4 measurement ID on the widget empty, or you will count each booking twice.

GA4 without GTM#

If your page loads GA4 with gtag.js, add your measurement ID (G-…) in the widget's Tracking tab. The loader then sends:

Widget eventGA4 event
widget_viewedbookingsxp_view
slot_selectedbookingsxp_slot
form_startedbookingsxp_form_start
booking_completedgenerate_lead and bookingsxp_booked

Each call looks like this; parameters without a value are left out:

JavaScript
gtag("event", "generate_lead", {
  send_to: "G-ABC123XYZ",
  service_name: "Initial consultation",
  staff_name: "Sam Lee",
  value: 60,
  currency: "GBP",
});

Other widget events are not sent to GA4 directly. Use GTM on the dataLayer for those. In GA4, mark generate_lead (or bookingsxp_booked) as a key event.

Add your conversion ID (AW-123456789, the AW- is added if you leave it out) and conversion label in the Tracking tab. Your page needs the Google tag (gtag.js) with your Ads account configured. On booking_completed the loader sends:

JavaScript
gtag("event", "conversion", {
  send_to: "AW-123456789/AbCdEfGhIjKlMnOp",
  transaction_id: "BXP-7K3M9Q",
});

The booking reference is the transaction_id, so Google Ads de-duplicates a conversion that is reported twice.

Enhanced conversions#

Turn on Enhanced conversions in the Tracking tab to improve matching. The widget hashes the visitor's email with SHA-256 in the browser, lower-cased and trimmed, and the plain email never leaves the widget for this purpose. The loader adds it to the conversion:

JavaScript
gtag("event", "conversion", {
  send_to: "AW-123456789/AbCdEfGhIjKlMnOp",
  transaction_id: "BXP-7K3M9Q",
  user_data: { sha256_email_address: "5b2c…e91f" },
});

The hash is also in the dataLayer event as bookingsxp.emailSha256, if you prefer to pass it on from GTM. Mention enhanced conversions in your privacy notice before you turn it on.

Meta Pixel (Pro)#

Add your Pixel ID. With the Meta Pixel on your page, the loader fires:

JavaScript
// on widget_viewed
fbq("track", "ViewContent");

// on booking_completed
fbq("track", "Schedule", {}, { eventID: "BXP-7K3M9Q" });

eventID is the booking reference. If you also send Schedule from a server through the Conversions API, use the same reference as event_id and Meta counts it once. You can get the reference server-side from a webhook.

LinkedIn (Pro)#

Add your LinkedIn partner ID and conversion ID. With the Insight Tag on your page, the loader fires on booking_completed:

JavaScript
window.lintrk("track", { conversion_id: 1234567 });

Thank-you page redirect#

Set a redirect URL in the Tracking tab, or the redirect-url attribute on the page, and the visitor is sent to your page after booking. Any analytics tool that can count a page view can then count bookings.

HTML
<bookingsxp-widget
  widget="w_8fk2m1qz"
  redirect-url="https://www.example.com/thank-you?ref={booking_id}&service={service}"
></bookingsxp-widget>

{booking_id}, {service} and {start} are replaced and URL-encoded. The loader waits 600 ms so pixels finish sending, then navigates the whole page, not just the iframe. Details in Embed attributes.

Attribution in Microsoft Bookings#

Separate from your analytics, BookingsXP writes where the booking came from into the booking notes in Microsoft Bookings, so it shows in Outlook, Teams and the Bookings app:

Text
— Booked on your website · Ref BXP-7K3M9Q
Source: google / cpc · Campaign: brand (Paid search)
Keyword: physio near me
First page: example.com/pricing
Booked from: example.com/book
Referrer: google.com
Ad click: gclid

Lines appear only when there is something to show. The source comes from UTM parameters first, then ad click IDs (gclid, gbraid, wbraid, msclkid, fbclid, li_fat_id, ttclid), then the referrer. Channels follow GA4's default grouping: Paid search, Paid social, Organic search, Organic social, Email, Referral, Direct and Other. UTM and click-ID parameters are removed from the page paths shown. The block holds no personal data.

The loader keeps the first campaign touch for 90 days in the visitor's browser, so a visitor who clicks an ad on Monday and books on Thursday is still credited to the ad. See Privacy & data for how this works with consent.

Turn it off with Write source & campaign into the booking notes in the Tracking tab. You can also have BookingsXP answer one custom question on your Bookings page (for example "How did you hear about us?") with the source, so it shows in Microsoft's own export.

Checking it works#

  1. Open your page with ?utm_source=test&utm_medium=cpc&utm_campaign=docs on the URL.
  2. In GTM Preview (or the browser console, with window.dataLayer), watch for bookingsxp.widget_viewed.
  3. Make a test booking. You should see bookingsxp.booking_completed, the GA4 and pixel calls in the network tab, and the attribution block in the appointment's notes in Microsoft Bookings.
  4. Cancel the test appointment in Microsoft Bookings as usual.

Edit or question? hello@bookingsxp.com