Funnel & CRM platforms

GoHighLevel Form Listener for GTM: Inline and Iframe Embeds

Tracks GoHighLevel (LeadConnector) inline and iframe form submissions in GTM, reading the verified lead message from cross-origin iframes and excluding calendar bookings.
EC-ready · Iframe-aware · CAPI dedupe · Tracks failures

Free and MIT licensed. Paste it into a GTM Custom HTML tag. No plugin or code change on the site.

At a glance

Version

3.0.1

Updated

July 5, 2026

Success event

ghl_form_success

Failure event

ghl_form_failed

Detection

Verified iframe postMessage + inline render

Redirects

Yes: pagehide fallback and same-domain thank-you recall

Enhanced Conversions

Yes: email, phone, name (inline and iframe)

Dependencies

None

Tag size

46.1 KB

License

MIT

What lands in your dataLayer

One clean event per real lead

Every success carries an event ID for Meta deduplication, the detection method that fired, and normalized contact fields you can map straight into Enhanced Conversions. Keep the PII keys out of GA4.

				
					{
  event: "ghl_form_success",
  ec_event_id: "uuid-v4",
  ec_detection_method: "postmessage",
  ec_tracker_version: "3.0.1",
  ec_name: "Jane Doe",
  ec_email: "jane@example.com",
  ec_phone: "+15551234567",
  form_url: "https://example.com/landing-page",
  form_cta: "",
  form_platform: "ghl_iframe",
  form_position: "top",
  form_index: 1,
  form_id: "form-id",
  ec_raw_fields: {
    email: {
      value: "jane@example.com",
      type: "email",
      _bucket: "email"
    }
  }
}
				
			

Why this listener exists

GoHighLevel forms are usually embedded as a cross-origin iframe from leadconnectorhq.com, so GTM’s built-in triggers cannot see inside them and click tracking counts nothing useful.

This listener handles both embed types. For iframes it accepts only messages from LeadConnector, msgsndr or GoHighLevel domains that carry a lead identifier (email, phone or name), and ignores booking and calendar messages. For inline forms it watches the form state itself.

Most form tracking fires on a button click or a thank-you page view. Clicks count validation failures and repeat clicks. Thank-you page views count refreshes, back-button visits and bookmarked links. This listener watches what GoHighLevel actually renders, so the event is much closer to a real lead.

How it detects a real submission

ghl_form_success fires on the first of these success paths:

  • Iframe: a cross-origin message from leadconnectorhq.com, msgsndr.com or gohighlevel.com containing a lead payload
  • Inline: the form removed or hidden after submit
  • Inline: a node replacement during the submit window
  • A redirect, caught on pagehide inside the submit window
  • A same-domain thank-you page, matched to recent stored form data

ghl_form_failed fires for inline forms when a visible error renders after the visitor has interacted with the form. Iframe validation errors are not visible to the parent page, so no failure event fires for iframe embeds.

Every event carries ec_detection_method, so you can segment reports by how each lead was detected and see which signals your site actually uses.

ec_detection_method Event What it means
postmessage Success A verified cross-origin message from the form iframe
form_removed Success The form was removed or hidden after a valid submit
generic_node Success A new node replaced the form during the submit window (weaker signal)
stored_recall Success Same-domain thank-you page, matched to data stored at submit
pagehide Success The page unloaded inside the submit window with no error showing (fallback)
error_class Failure The form gained the platform’s error class
error_render Failure An error message rendered after the visitor interacted

Install it in Google Tag Manager

  1. Download the GTM tag above, or copy gohighlevel-form-tracker.gtm.html from the GitHub repository.
  2. In GTM, create a Custom HTML tag and paste the file in. It already includes the <script> wrapper.
  3. Trigger it on All Pages (Page View), or on Consent Initialization if your consent setup needs the tracker available early.
  4. Create a Custom Event trigger for ghl_form_success. Use the regex ^ghl_form_(success|failed)$ if you also want failures.
  5. Create Data Layer Variables for the keys you need (table below), then attach your GA4, Google Ads, Meta or server-side GTM tags to the trigger.
  6. Open Preview, submit a real test form and confirm ghl_form_success appears with the expected ec_detection_method. Then publish.

Retire any old click or thank-you page conversion for the same form, otherwise each lead is counted twice.

Events and dataLayer keys

Key What it holds
event ghl_form_success, ghl_form_failed, ec_form_interaction (first real input) or ec_tracker_initialized (script loaded)
ec_event_id UUID per event. Pass it to Meta as the event ID so browser and CAPI events deduplicate
ec_detection_method Which success or failure path fired (see above)
ec_tracker_version Script version, useful when you audit containers later
ec_email, ec_phone, ec_name Normalized PII from the form (phone in E.164 where possible). Removed when PII consent is denied
ec_email_sha256, ec_phone_sha256 SHA-256 hashes, added when hashPii: true (needs HTTPS)
ec_raw_fields Every captured field with a _bucket classification. Keep it out of GA4
form_id, form_platform Form identifier and platform name
form_position, form_index Where the form sits on the page (top, middle, footer) and its order, for multi-form pages
form_url, form_cta Page URL and the submit button text
ec_pii_redacted true when PII consent is denied and PII keys were stripped

Using it for Enhanced Conversions and Meta CAPI

  • Google Ads Enhanced Conversions: map ec_email and ec_phone (or the _sha256 versions) into a User-Provided Data variable on your conversion tag.
  • Meta Pixel and CAPI: send ec_event_id as the event ID on both the browser and server event so Meta counts the lead once.
  • GA4: do not send raw ec_* PII or ec_raw_fields to GA4. Its terms prohibit PII in event parameters. Send form_id, form_platform and ec_detection_method instead.
  • Duplicates: with dedupe: true (the default), a repeat success for the same form, email or phone within 5 minutes is suppressed.

Configuration and consent

Set window.EC_FORM_CONFIG before the tag loads to change the defaults:

window.EC_FORM_CONFIG = {
  debug: false,            // [EC] console logs, Preview only
  hashPii: false,          // add ec_email_sha256 / ec_phone_sha256
  dedupe: true,            // suppress repeat success within 5 min
  ttlMs: 600000,           // freshness window for thank-you recall
  defaultCountryCode: "1", // phone normalization fallback
  extraThankYouPatterns: [] // extra thank-you URL substrings
};

The tracker checks consent before it fires or writes storage. It auto-detects Google Consent Mode v2, OneTrust and Cookiebot. With analytics consent denied, nothing fires and nothing is stored. With PII consent denied, events still fire but email, phone, name and hashes are removed. Any other CMP can be wired in with window.EC_FORM_CONSENT_CHECK. If no CMP or override is found, the tracker assumes full consent, so match it to your own legal requirements.

Test it before you publish

  • Submit a valid form. Expect one ghl_form_success.
  • Submit with a required field empty. Expect ghl_form_failed (inline forms only) and no success event.
  • Fix the error and resubmit. Expect one success (recovery is allowed).
  • Refresh the confirmation or thank-you page. Expect nothing new.
  • If the page has two forms, submit each and check form_position and form_index.
  • Run window._ecFormTrackers.ghl.status() in the console to see version, consent state, attached forms and the last event.

Troubleshooting

  • No ec_tracker_initialized in Preview? The tag is not firing on that page, or consent for analytics is denied.
  • Events in Preview but not live? Make sure the container is published, and that a cache or script optimizer (for example WP Rocket delay JS or Cloudflare Rocket Loader) is not deferring GTM.
  • Set debug: true in EC_FORM_CONFIG to see [EC] logs while testing.

Known limitations

  • Iframe validation failures cannot be observed from the parent page.
  • The iframe parser follows GoHighLevel’s current message shape. If GHL changes it, the iframe path needs an update.
  • pagehide is a fallback, and generic_node can be noisy when unrelated content changes near an inline form.
  • A redirect to a different domain cannot use same-domain recall.
  • Bot or spam submissions that pass the platform’s own validation still count as success.
  • Phone normalization is best-effort. The raw value stays in ec_raw_fields when PII consent allows it.

Changelog

  • 3.0.1: first public standalone release. Confirmation-render detection, success and failure events, consent gate (Consent Mode v2, OneTrust, Cookiebot), PII redaction, optional SHA-256 hashing, 5-minute dedupe, ec_event_id, thank-you recall and the status() debug API.

On this page

Want it installed and verified?

We install the listener, wire GA4, Google Ads Enhanced Conversions and Meta CAPI, and check the numbers against your CRM.

Keep going

More GTM form listeners

Multi-platform

Universal GTM Form Tracker: One Tag for Nine Form Platforms

One GTM tag that detects the form platform on the page and tracks real confirmations for Gravity Forms, Elementor Pro, Contact Form 7, WPForms, GoHighLevel, Unbounce, SwipePages, Kartra and Squarespace.
9 platforms, One tag, CAPI dedupe, Container import
Embedded form builders

Jotform Listener for GTM: Track Redirecting Forms Without Thank-You Page Triggers

Tracks Jotform submissions in GTM even when the form redirects to a thank-you page, and never counts a refresh, back button or direct visit to that page.
Redirect-safe · EC-ready (source embeds) · CAPI dedupe · 88 tests
v3.3.0-jotform.1
WordPress forms

Gravity Forms Listener for GTM: GA4, Enhanced Conversions and Meta CAPI

Tracks real Gravity Forms submissions in GTM, including AJAX confirmations, postback pages and same-domain thank-you redirects, with hashed email and phone for Enhanced Conversions.
EC-ready · Redirect-safe · CAPI dedupe · Tracks failures

When the numbers still do not match

Your form fires. Does the conversion match the CRM?

A listener fixes detection. If Google Ads, Meta and GA4 still disagree with your actual leads, the problem is usually elsewhere in the container, the consent setup or the CRM hand-off.