Skip to main content
Gravity Forms → GA4Integration guide

Connecting Gravity Forms to GA4

Gravity Forms stores the entry in your own WordPress database, which makes it one of the easier sources to join correctly. GA4 is where the business goes to understand what happened, which makes an unattributed conversion there expensive in decisions rather than in ad spend. The join between them succeeds or fails on one thing: whether the GA4 client_id reaches the Gravity Forms entry before the conversion happens, because GA4 can only match a conversion it can tie back to a click it recognizes.

Free30 minutesNo obligation

Specific to this pair

Gravity Forms to GA4: read _ga in the hook, not a hidden field

Skip hidden fields for GA4. In gform_after_submission, read the _ga cookie for client_id and the measurement-specific cookie for session_id, then send generate_lead through Measurement Protocol with the form ID. Disable the Gravity Forms GA add-on or Tag Manager triggers to avoid doubles, mark only lead forms as key events, and skip spam.

For GA4 you do not need dynamic population at all, which sidesteps the caching problem. The submission is a POST from the visitor's browser, never served from cache, and it carries the visitor's cookies. Inside gform_after_submission, read the _ga cookie from the request and take the last two dot-separated parts as the client_id; read the _ga_ cookie for your measurement ID to get the session_id. Then send generate_lead through Measurement Protocol with both, plus the form ID as a parameter.

Check whether you also have Gravity Forms' own Google Analytics add-on enabled, or a Tag Manager trigger on the confirmation. Either of those plus your server event means two generate_lead events per entry, and GA4 does nothing to collapse them. Pick the server hook, because AJAX forms that show an inline confirmation and forms that redirect to another page both run the same PHP hook, while browser triggers have to be built separately for each confirmation type.

Mark generate_lead as a key event only for the forms that are leads. A site with a contact form, a newsletter signup and a job application all on Gravity Forms should pass a form name parameter, and the newsletter and careers forms should not count as key events. Skip entries Gravity Forms flags as spam before sending.

Gravity Forms → GA4 · what breaks

Why this join usually fails — Gravity Forms → GA4

  1. 01

    The GA4 client_id never reaches Gravity Forms

    The identifier must be written into a hidden field with dynamic population enabled, and that only works if the parameter is on the URL when the page renders. Page caching serves a cached render to the visitor, so the dynamic population never runs — the same caching problem that breaks WooCommerce.

  2. 02

    Dynamic population fails silently under page caching

    The field is configured correctly and still arrives empty, because the visitor was served a cached page rendered for someone else. This is the most common Gravity Forms failure and it looks like nothing is wrong.

  3. 03

    Everything lands under (direct)/(none)

    The classic Measurement Protocol symptom, and it always means the same thing: the client_id was missing or wrong, so GA4 had no session to attach the event to and invented a new user.

  4. 04

    Nothing reconciles afterwards

    GA4 DebugView shows events arriving with their parameters, and Realtime confirms the user and session they attached to. Neither tells you whether you are double-counting — for that, compare GA4's conversion count against the source system's record for the same window.

Gravity Forms → GA4 · the fix

What working looks like — Gravity Forms → GA4

  • The GA4 client_id on every entry

  • Conversions arriving in GA4

    Conversions appear in GA4 attributed to the original session's source and medium, so acquisition reporting reflects what actually drove revenue.

  • Reconciled against the source

Gravity Forms → GA4 · architecture

How Gravity Forms and GA4 actually connect

  1. 1

    Gravity Forms holds the truth

    The entry lives in your database with every field value attached. You can query it, back it up and reconcile against it without depending on any third party, which is a real advantage over hosted form tools.

  2. 2

    GA4 needs a click to match

    GA4 needs the client_id to attach a server event to the user and session that produced the click. Without it there is no attribution to inherit and the event is orphaned.

  3. 3

    The identifier is the bridge

    The GA4 client_id, captured at the visit and carried into the Gravity Forms entry.

  4. 4

    The event source decides reliability

    Fire server-side from the PHP hook. This runs regardless of caching, AJAX submission, or what the confirmation page does.

  5. 5

    Deduplication at the destination

    GA4 has no built-in deduplication for Measurement Protocol. If the browser also sends the event, it counts twice. The only reliable approach is to decide per event which side sends it, and enforce that decision — GA4 will not protect you from your own duplicates.

Gravity Forms → GA4 · normal or broken

Working vs. broken, side by side — Gravity Forms → GA4

Normal, not a fault

  • The GA4 client_id present on the entry

  • Sent from the gform_after_submission hook

  • Deduplicated correctly

    GA4 has no built-in deduplication for Measurement Protocol. If the browser also sends the event, it counts twice. The only reliable approach is to decide per event which side sends it, and enforce that decision — GA4 will not protect you from your own duplicates.

  • Reconciles with the source

Actually broken

  • The GA4 client_id missing on most records

    The identifier must be written into a hidden field with dynamic population enabled, and that only works if the parameter is on the URL when the page renders. Page caching serves a cached render to the visitor, so the dynamic population never runs — the same caching problem that breaks WooCommerce.

  • Sent from the browser

    The field is configured correctly and still arrives empty, because the visitor was served a cached page rendered for someone else. This is the most common Gravity Forms failure and it looks like nothing is wrong.

  • Counted twice, or not at all

    The classic Measurement Protocol symptom, and it always means the same thing: the client_id was missing or wrong, so GA4 had no session to attach the event to and invented a new user.

  • Nobody has reconciled it

Gravity Forms → GA4 · diagnose

Diagnostic order — Gravity Forms → GA4

  1. 01

    Count entrys carrying the GA4 client_id

  2. 02

    Follow one real conversion end to end

  3. 03

    Submit a test entry through a cached page

    Not through a logged-in admin session, which bypasses the cache. If the hidden field is empty on the cached path and populated on the admin path, caching is your cause.

  4. 04

    Check whether server events carry a session and a source

    In GA4 Realtime or DebugView, find the event and look at its session and traffic source. A brand-new user with no source on every server event is the missing-client_id signature.

  5. 05

    Read the match rate, not the success message

    GA4 DebugView shows events arriving with their parameters, and Realtime confirms the user and session they attached to. Neither tells you whether you are double-counting — for that, compare GA4's conversion count against the source system's record for the same window.

Gravity Forms → GA4 · prove

How it gets proven — Gravity Forms → GA4

Source of truth

The Gravity Forms entries list for the same window, or the wp_gf_entry table directly.

  • The GA4 client_id confirmed present on a live entry.
  • Server events confirmed in DebugView attaching to an existing session with the original traffic source intact.
  • Entry meta confirmed populated on a submission made from a fully cached page as an anonymous visitor.

Gravity Forms → GA4 · free audit

What we check in the free audit

  • Count entrys carrying the GA4 client_id
  • Follow one real conversion end to end
  • Submit a test entry through a cached page
  • Check whether server events carry a session and a source
  • Read the match rate, not the success message

Checked against

The Gravity Forms entries list for the same window, or the wp_gf_entry table directly.

Get my free conversion tracking audit

Free30 minutesNo obligation

Gravity Forms → GA4 · when not to buy

When you don't need this — Gravity Forms → GA4

  • Measure identifier coverage yourself first — pull your last hundred entrys and count how many carry the GA4 client_id.
  • If your site has no caching layer and one form, a developer can wire this in an afternoon. Worth trying before hiring anyone.
  • GA4 is reporting, not bidding. If your problem is ad platform optimization, fix the ad platform destination first — GA4 will not change what any campaign does.

Gravity Forms → GA4 · what we deliver

What gets built — Gravity Forms → GA4

  • Identifier capture into Gravity Forms

    Hidden field with 'allow field to be populated dynamically' enabled and a parameter name set, plus a cookie fallback via a gform filter so the identifier survives a visitor who browsed several pages before converting.

  • Event source: the gform_after_submission hook

    Fire server-side from the PHP hook. This runs regardless of caching, AJAX submission, or what the confirmation page does.

  • Dispatch to GA4

    Measurement Protocol events with the client_id, session_id and the correct measurement ID and API secret, sent server-side.

  • Reversals where they exist

    Nothing to reverse, though entries marked spam should be excluded from the send.

Written guarantee

95%+ tracking accuracy

Measured against The Gravity Forms entries list for the same window, or the wp_gf_entry table directly.. Miss it and we keep working at no cost.

Get my free conversion tracking audit

From $400 · See packages

FAQ

Gravity Forms → GA4 questions, answered

Read the _ga cookie from the request inside the gform_after_submission hook; the submission POST carries the visitor's cookies even when the page itself was cached. The client_id is the last two numeric parts of the cookie value.

Free · 30 min

Get Gravity Forms and GA4 joined properly

Free30 minutesNo obligation