How to Track GoHighLevel Form Submissions and Booking Completions Using Google Tag Manager

If you are using GoHighLevel forms or calendar widgets on your website, one of the most common issues is that standard Google Tag Manager form triggers do not work reliably.

Why?

Because most GoHighLevel embeds run inside iframes and communicate through browser messages instead of native HTML form submissions.

That means if you rely on GTM’s built-in form submission trigger, you will likely miss conversions.

In this guide, I’ll show you how to properly track GoHighLevel form submissions and booking completions using an event listener.

Why GoHighLevel Tracking Requires a Custom Listener

Unlike regular website forms, GoHighLevel embedded forms and calendars:

  • Run inside an iframe
  • Do not trigger browser form submit events
  • Send submission data through postMessage

Because of that, GTM cannot detect successful submissions out of the box.

The solution is to listen for those iframe messages manually and push them into the dataLayer.

What This Setup Tracks

With this listener, you can capture:

  • Successful GoHighLevel form submissions
  • Booking completions from calendar widgets
  • Submitted lead information
  • Customer ID and contact details

This gives you clean conversion events for analytics and ad platforms.

Step 1: Add the GoHighLevel Event Listener

Create a Custom HTML Tag in GTM and add the script below.

Fire it on All Pages or DOM Ready.

<script>

(function () {

  var cachedInputData = {};

  window.dataLayer = window.dataLayer || [];

  window.addEventListener(‘message’, function (event) {

    if (Object.prototype.toString.call(event.data) !== ‘[object Array]’) {

      return;

    }

    var inputJSON = event.data[2];

    if (

      inputJSON &&

      typeof inputJSON === ‘string’ &&

      inputJSON.includes(‘full_address’) &&

      inputJSON.includes(‘customer_id’) &&

      inputJSON.includes(‘full_name’) &&

      inputJSON.includes(’email’)

    ) {

      try {

        var parsedInputs = JSON.parse(inputJSON);

        cachedInputData = parsedInputs;

        dataLayer.push({

          event: ‘ghl_form_submit’,

          inputs: parsedInputs

        });

      } catch (err) {

        console.error(‘GHL Listener JSON Parse Error:’, err);

      }

    }

    if (event.data[0] === ‘msgsndr-booking-complete’) {

      dataLayer.push({

        event: ‘ghl_booking_complete’,

        inputs: cachedInputData

      });

    }

  });

})();

</script>

How the Script Works

Let’s break down what happens behind the scenes.

It Listens for GoHighLevel Messages

The script waits for iframe messages sent from the embedded GoHighLevel widget.

It Detects Form Submission Payloads

When the message contains lead data such as:

  • Email
  • Full name
  • Address
  • Customer ID

it treats that as a successful form submission.

Then it pushes:

event: ‘ghl_form_submit’

to the dataLayer.

It Tracks Booking Completion Separately

When GoHighLevel sends:

msgsndr-booking-complete

the script pushes:

event: ‘ghl_booking_complete’

It Preserves Lead Data for Booking Events

The submitted form inputs are cached temporarily so the booking completion event can include them as well.

This is useful when a user fills out details before booking an appointment.

Step 2: Create GTM Custom Event Triggers

You need two triggers.

Form Submission Trigger

Trigger Type: Custom Event

Event Name:

ghl_form_submit

Booking Completion Trigger

Trigger Type: Custom Event

Event Name:

ghl_booking_complete

Step 3: Create Data Layer Variables

Because the input data is nested inside the inputs object, create variables using dot notation.

Examples:

Variable NameData Layer Variable
Emailinputs.email
Nameinputs.full_name
Customer IDinputs.customer_id

Step 4: Send Conversion Events to Your Platforms

Now you can use these triggers to fire:

For Form Submissions

  • GA4 Lead Event
  • Google Ads Conversion
  • Meta Lead Event

For Booking Completions

  • GA4 Schedule Appointment Event
  • Qualified Lead Conversion
  • Meta Schedule Event

Step 5: Test the Setup

Open GTM Preview Mode and test:

  1. Submit a GoHighLevel form
  2. Complete a booking

You should see:

ghl_form_submit

ghl_booking_complete

Verify that the inputs object contains the expected user data.

Common Mistakes to Avoid

Using Native Form Submission Trigger

This usually does not work for GoHighLevel iframe embeds.

Not Loading the Listener Early Enough

Load the script on:

  • DOM Ready
    or
  • All Pages

Forgetting Nested Data Layer Paths

Remember:

inputs.email

not just:

email

Final Thoughts

Tracking GoHighLevel forms and bookings properly requires more than GTM’s default triggers.

Because the platform relies heavily on iframe embeds and postMessage communication, a custom listener is the most reliable way to capture conversions.

Once implemented, you get:

  • Accurate lead tracking
  • Reliable booking attribution
  • Full submitted user data for enhanced conversions
  • Better optimization signals for your ad platforms

If you are running paid traffic to GoHighLevel forms or calendars, this setup is essential for trustworthy reporting.