← All Guides

Acuity Scheduling Booking Tracking with Google Tag Manager: GA4 and Google Ads Conversions from Embedded Appointments

Track completed Acuity Scheduling appointments from an embedded scheduler with Google Tag Manager. Covers the postMessage listener, cross-domain setup for the popup and redirect embeds, GA4 and Google Ads tags, booking values and testing.

Atiqul Islam
Written by Atiqul Islam

Tracking & analytics specialist. 278+ GTM, GA4 and server-side tracking projects for clients in the US, UK and Australia.

Rather not do this yourself? I set this up for clients every week. Free 15-minute audit, no obligation.

Book a Free Audit

Acuity Scheduling, now part of Squarespace, powers bookings for salons, clinics, tutors, photographers and consultants. Like every hosted scheduler, the appointment is confirmed inside Acuity's iframe, so your website's Google Tag Manager sees nothing unless you listen for the message Acuity sends when a booking completes.

This guide covers the listener, the GA4 and Google Ads tags, values, the cross-domain cases, and how to test.

The Three Embed Types

Check your site and confirm which one you have before setting anything up.

Step 1: Confirm What Acuity Sends

Before writing the listener, open the page with the scheduler, open the browser console and run:

window.addEventListener('message', function (e) { console.log(e.origin, e.data); });

Complete a test booking. You will see Acuity messages for sizing and, on completion, a message that identifies the scheduling confirmation. The exact string has changed between Acuity versions, so confirm it on your site. In my implementations it contains a scheduling complete identifier.

Step 2: The Listener Tag

Create a Custom HTML tag named Listener - Acuity on the pages with the scheduler:

<script>
(function () {
  window.addEventListener('message', function (e) {
    if (!e.origin || e.origin.indexOf('acuityscheduling.com') === -1) { return; }
    var data = e.data;
    if (typeof data !== 'string') {
      try { data = JSON.stringify(data); } catch (err) { return; }
    }
    if (data.indexOf('scheduling_complete') === -1 && data.indexOf('acuity:appointment') === -1) { return; }

    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'acuity_booking',
      booking_tool: 'acuity',
      booking_status: 'complete'
    });
  });
})();
</script>

Adjust the two match strings to whatever you saw in Step 1. The origin check keeps other iframes from triggering it.

Step 3: Variables and Trigger

Data Layer Variables for booking_status and, if you add them later, appointment_type and booking_value. A Custom Event trigger CE - acuity_booking with the condition booking_status equals complete.

Step 4: GA4 and Google Ads Tags

Step 5: Values Per Appointment Type

If your Acuity scheduler is embedded with the appointment type preselected in the URL, read the type from the embed URL with a Custom JavaScript variable and push it with the booking event. Then create a Lookup Table variable mapping each type to its value and use it in the Google Ads tag. This turns one generic booking conversion into value-aware data without changing anything in Acuity.

When the booking happens on Acuity's domain:

  1. In the Conversion Linker, enable linking across domains and list your domain and the Acuity domain you use.
  2. Add both domains to the cross-domain list in your Google tag settings so GA4 keeps the session.
  3. Use Acuity's confirmation page tracking code setting, if available on your plan, to load your GTM container or fire the conversion on the confirmation page.
  4. Test that the click identifier survives the hand-off by arriving on your site with a test gclid, clicking through to Acuity, and checking the linker parameter on the Acuity URL.

If none of this is possible, track the click into Acuity as a secondary conversion and import confirmed appointments from Acuity's export as offline conversions.

Step 7: Enhanced Conversions

The iframe message does not include the client's email. If you want Enhanced Conversions, add a short email step on your page before the scheduler loads and prefill Acuity with it. Push the email to the dataLayer at that step, create a User-Provided Data variable from it and attach it to the Google Ads conversion tag. The Calendly guide on this site shows the same pattern.

Step 8: Test

  1. GTM Preview on the scheduler page. Complete a test booking.
  2. Confirm one acuity_booking event and one fire each of GA4 and Google Ads.
  3. Inspect the Google Ads request in a tag debugger such as the Insighter Debugger extension for the label and value.
  4. Refresh the page after booking. Nothing should fire again.
  5. Cancel the test appointment in Acuity.

Common Problems

Outcome

Google Ads counts appointments, not scheduler views. Values per appointment type let the account distinguish a consultation from a quick follow-up. And GA4 shows which channels fill the calendar, which is the question every booking-led business is really asking.

Frequently Asked Questions

Which Acuity embed should I use for the best tracking?

The inline iframe embed on your own page is the easiest to track, because Acuity posts a message to your page when the appointment is confirmed. The popup and direct-link options send the visitor to Acuity's domain and need cross-domain measurement.

Can I pass the appointment value to Google Ads?

The confirmation message does not reliably include the price. Use a fixed value per appointment type in Google Ads, or map appointment types to values with a lookup table in GTM if the type is available in the message or URL.

Can I get the client's email for Enhanced Conversions?

Not from the iframe message. Collect the email on your page before loading the scheduler and prefill Acuity with it, or use Acuity's own conversion tracking settings inside the scheduler for a separate confirmation signal.

Does Acuity have built-in conversion tracking?

Acuity lets you add tracking code to the confirmation page in its settings on some plans. That fires inside Acuity's domain and does not carry your Google Ads click identifier unless cross-domain linking is configured, so the parent-page method in this guide is preferred for attribution.

Why does my booking fire twice?

Both the parent-page listener and Acuity's internal tracking code are active, or the listener matches more than one message. Keep one method and match only the completion message.

Want This Done Right the First Time?

Book a free 15-minute audit call. I'll review your setup, show you what is broken, and tell you exactly what it takes to fix it.

Chat Now