If you’re tracking form submissions using a thank you page, you’ve probably run into this problem:
👉 Users refresh the page and your conversion fires again.
This leads to inflated numbers in GA4, Meta Ads, or any other platform you’re using.
There are two main ways to fix this:
- Using an ID in the URL
- Controlling duplication directly in the browser (recommended)
Let’s break both down.
Option 1: Add an ID to the Thank You Page URL
The idea here is simple: every time a form is submitted, you append a unique identifier to the URL.
Example:
https://sanrivalina.com/thank-you-page/?entry_id=12345
How to implement it (WPForms)
WPForms does NOT reliably expose entry_id as a Smart Tag in the redirect URL. So if you want the real entry ID, you’ll need a small PHP filter:
add_filter( 'wpforms_process_redirect_url', function( $url, $form_id, $fields, $form_data, $entry_id ) {
return $url . '?entry_id=' . $entry_id;
}, 10, 5 );
If you don’t want to use code, you can pass field values instead:
https://sanrivalina.com/thank-you-page/?email={field_id="1"}
Pros
- You get a unique identifier per submission
- Useful for debugging or backend matching
Cons
- Requires PHP for real entry IDs
- The same URL can still be refreshed (duplicates still possible)
- Users can share the URL
- Not ideal for clean tracking setups
👉 Important: This does NOT solve duplication by itself.
Option 2: Prevent Duplicates with sessionStorage (Recommended)
Instead of relying on the URL, you control duplication directly in the browser.
The idea:
👉 Once the conversion fires, you store a flag in the session.
👉 If the page reloads, the flag blocks the trigger.
Step 1: Create a Variable in GTM
Type: Custom JavaScript
function() {
return sessionStorage.getItem('lead_form_contact');
}
Step 2: Create Your Trigger
Name:
TR - Pageview - Thank You Page
Conditions:
- Page URL contains
thank-you-page - AND
JS - Session - Lead Contactdoes not equaltrue
This is the key piece. This condition is what blocks duplicates.
Step 3: GA4 Event Tag
Name:
GA4 - Event - Lead Contact
Trigger:
TR - Pageview - Thank You Page
Step 4: Store the Flag (Custom HTML Tag)
Name:
UTIL - Session Flag - Lead Contact
<script>
sessionStorage.setItem('lead_form_contact', 'true');
</script>
Trigger:
👉 Use the SAME trigger as the GA4 event
What’s actually happening?
First visit
- No flag exists
- Trigger conditions pass
- GA4 event fires
- Flag is stored
Page reload
- Flag already exists
- Trigger condition fails
- Nothing fires
That’s it. No duplicates.
Which Option Should You Use?
If your goal is clean, reliable tracking:
👉 Go with sessionStorage.
If your goal is backend validation or debugging:
👉 You can add an ID to the URL (but don’t rely on it for tracking logic).
Final Recommendation
Use this setup:
- Thank you page trigger
- sessionStorage flag
- Clean URL (no parameters required)
It’s simple, scalable, and aligns with how tracking is actually handled in production environments.
If you want to take it one step further, the best setup is to fire the conversion on form submission (not page load), but that’s a different level of implementation.
For most cases, this approach will keep your data clean and reliable.
