2026-07-20
Contact Form 7 Submissions Showing (not set) in GA4? Here's the GTM Fix
You submit a test lead through your Contact Form 7 form, open GA4, and the event either doesn't show up at all or lands in a report as (not set) or Unassigned. Your channel and campaign reports are now useless for judging which campaigns actually drive form fills, which is a problem if you're pulling that CSV into anything downstream.
Why this happens
- No GTM trigger is listening for CF7's own event. CF7 fires a native JavaScript event called
wpcf7mailsenton successful submission, but GTM does nothing with it unless you build a Custom Event trigger for it. Most setups instead try to trigger on a generic Form Submission trigger, which doesn't reliably fire for CF7's AJAX-based submit. - The GA4 event tag isn't sending source/medium or session data. If the event fires but session parameters like
source,medium, orcampaignaren't attached (because the event fires after a page reload, or in an iframe, or the session already expired), GA4 falls back to (not set). - The dataLayer push happens before GTM has loaded, so GTM's Custom Event trigger never catches it — common when CF7's script runs early or a caching plugin reorders scripts.
- The GA4 Configuration tag fires after the event tag, or on a different trigger, so the event tag sends data without an initialized GA4 client, producing orphaned hits.
- Consent Mode or a cookie banner is blocking the GA4 tag from firing at all until consent is granted, and the CF7 submission event happens before that.
Fix, step by step
- In WordPress, confirm Contact Form 7 is actually emitting
wpcf7mailsent— this is standard behavior since CF7 v5.1+, no extra plugin needed. - Add the dataLayer listener snippet (below) to your theme's functions.php, or via a plugin like Insert Headers and Footers/Code Snippets. This pushes a clean
cf7_submitevent into the dataLayer whenever any CF7 form successfully mails. - In GTM, create a new Trigger → type Custom Event → Event name:
cf7_submit→ fires on All Custom Events (or restrict by Form ID variable if you track multiple forms). - Create a new Data Layer Variable in GTM named
DLV - Form IDpointing to the keyformId, and optionally one forformName, so you can pass form identity into GA4 as event parameters. - Create your GA4 Event tag: Tag type = Google Analytics: GA4 Event, Configuration Tag = your existing GA4 Configuration tag, Event Name =
generate_leadorform_submit(pick one and stay consistent), and add Event Parameters mappingform_idandform_nameto the Data Layer Variables you just built. - Set the trigger on this tag to the Custom Event trigger from step 3.
- Check your GA4 Configuration tag's trigger — it should fire on All Pages (Initialization or Page View), and confirm in GTM's tag sequencing that it fires before the new event tag, not after.
- If you use Consent Mode, confirm the GA4 tags have Additional Consent Checks set correctly and that your consent banner isn't blocking analytics_storage before the form event fires in your test session.
- Publish the GTM container.
Copy-paste template
// Add to functions.php or a code snippets plugin
add_action('wp_footer', function() {
?>
formId
[ ] Variable: DLV - Form Name -> formName
[ ] Tag: GA4 Event, name = generate_lead (or form_submit)
[ ] Tag fires AFTER GA4 Configuration tag
[ ] Event params: form_id = {{DLV - Form ID}}, form_name = {{DLV - Form Name}}
[ ] Container published
How to verify it worked
Open GTM's Preview mode, load the page with your CF7 form, submit a real test entry, and confirm cf7_submit appears in the Summary panel with your GA4 tag firing beneath it. Then switch to GA4's DebugView (Admin → DebugView), repeat the submission, and confirm your event name (e.g. generate_lead) appears in the real-time stream with form_id and form_name populated — not blank, not (not set).
Once this is firing cleanly, your GA4 export will actually attribute leads to the right campaign instead of dumping them into (not set) — which matters if you're feeding that CSV into Next Action Analyst to prioritize which campaigns deserve budget next.
Next Action Analyst turns your campaign export into a prioritized list of changes to make tomorrow — with the numbers that justify each one.