WPForms + Meta Ads Conversion Tracking Setup
I see this exact setup broken in about 35% of the WordPress accounts I audit. Usually it’s because the WPForms tracking was set up using the old wpformsFormSubmitted event (which doesn’t fire reliably) or they’re only using the Meta pixel without CAPI, missing 15-25% of conversions from iOS users and ad blockers.
What You’ll Have Working By The End
- WPForms submissions automatically tracked as ‘Lead’ events in Meta Ads
- Server-side conversion tracking through Meta CAPI with proper deduplication
- GTM setup that captures form data and passes it to Meta
- Testing workflow to verify both pixel and CAPI events are firing
- Cross-reference system to validate conversion counts between WPForms entries and Meta reporting
Prerequisites
- WPForms installed on WordPress (any version, including Lite)
- Meta Pixel installed on your site
- Google Tag Manager container with Publish access
- Meta Ads account with Events Manager access
- Meta Business account with CAPI access token
- Server-side GTM container (for CAPI) or webhook endpoint
Step 1: Set Up WPForms Data Layer Push
WPForms fires the wpformsAjaxSubmitSuccess event on successful submissions. You need to capture this and push form data to the data layer.
Add this code to your theme’s functions.php or a custom plugin:
function wpforms_meta_tracking_script() {
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Listen for WPForms AJAX success
document.addEventListener('wpformsAjaxSubmitSuccess', function(e) {
var formData = e.detail;
var form = e.target;
// Extract form fields - adjust field IDs based on your form
var email = form.querySelector('input[name*="[email]"]')?.value || '';
var firstName = form.querySelector('input[name*="[first]"]')?.value || '';
var lastName = form.querySelector('input[name*="[last]"]')?.value || '';
var phone = form.querySelector('input[name*="[phone]"]')?.value || '';
// Generate unique event ID for deduplication
var eventId = 'wpf_' + formData.form_id + '_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
// Push to data layer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'wpforms_submission',
'form_id': formData.form_id,
'form_title': formData.form_title || 'WPForms Submission',
'user_email': email,
'user_first_name': firstName,
'user_last_name': lastName,
'user_phone': phone,
'event_id': eventId,
'conversion_value': 0, // Set your lead value here
'currency': 'USD'
});
console.log('WPForms submission tracked:', eventId);
});
});
</script>
<?php
}
add_action('wp_footer', 'wpforms_meta_tracking_script');
Important: The field selectors above work for standard WPForms fields. If you’re using custom field names, inspect your form HTML and adjust the selectors accordingly.
Step 2: Create GTM Trigger
In GTM, create a Custom Event trigger:
- Trigger Type: Custom Event
- Event name:
wpforms_submission - Fire on: All Custom Events (or specific form IDs if you want granular control)
Save as “WPForms - Submission Success”
Step 3: Set Up Data Layer Variables
Create these Data Layer Variables in GTM:
- DLV - Form ID:
form_id - DLV - User Email:
user_email - DLV - User First Name:
user_first_name - DLV - User Last Name:
user_last_name - DLV - User Phone:
user_phone - DLV - Event ID:
event_id - DLV - Conversion Value:
conversion_value
Step 4: Configure Meta Pixel Tag
Create a new Meta Pixel tag in GTM:
- Tag Type: Meta Pixel
- Track Type: Track Custom Events
- Event Name:
Lead(use standard event for better optimization) - Event Parameters:
content_name: {{DLV - Form Title}} content_category: lead_form value: {{DLV - Conversion Value}} currency: USD - Advanced Parameters:
em: {{DLV - User Email}} fn: {{DLV - User First Name}} ln: {{DLV - User Last Name}} ph: {{DLV - User Phone}} event_id: {{DLV - Event ID}} - Trigger: WPForms - Submission Success
Which event should you use? Use ‘Lead’ for lead gen forms, ‘CompleteRegistration’ for signup forms, or create a custom conversion event in Meta Events Manager if you need campaign-specific tracking.
Step 5: Set Up Meta CAPI (Server-Side Tracking)
This is where most setups fall apart. You need CAPI for iOS 14.5+ users and ad blocker bypass.
Option A: Server-Side GTM Container
Create a server-side GTM container and add this tag:
- Tag Type: Meta Conversions API
- Event Name:
Lead - Event Parameters: Same as pixel tag
- User Data Parameters:
email: {{DLV - User Email}} first_name: {{DLV - User First Name}} last_name: {{DLV - User Last Name}} phone: {{DLV - User Phone}} - Event ID:
{{DLV - Event ID}}(critical for deduplication) - Test Event Code: Use your Meta test event code during setup
Option B: Direct CAPI Webhook
If you don’t have server-side GTM, add this to your WPForms success hook:
function send_wpforms_to_meta_capi($fields, $entry, $form_data) {
$access_token = 'YOUR_META_CAPI_ACCESS_TOKEN';
$pixel_id = 'YOUR_META_PIXEL_ID';
$test_event_code = 'TEST_12345'; // Remove in production
$event_id = 'wpf_' . $form_data['id'] . '_' . time() . '_' . wp_rand(1000, 9999);
$event_data = array(
'event_name' => 'Lead',
'event_time' => time(),
'event_id' => $event_id,
'event_source_url' => get_permalink(),
'user_data' => array(
'em' => array(hash('sha256', strtolower($fields[1]['value']))), // Email field
'fn' => array(hash('sha256', strtolower($fields[2]['value']))), // First name
'ln' => array(hash('sha256', strtolower($fields[3]['value']))), // Last name
),
'custom_data' => array(
'content_name' => $form_data['settings']['form_title'],
'content_category' => 'lead_form',
'value' => 0,
'currency' => 'USD'
)
);
$payload = array(
'data' => array($event_data),
'test_event_code' => $test_event_code // Remove in production
);
$response = wp_remote_post("https://graph.facebook.com/v18.0/{$pixel_id}/events?access_token={$access_token}", array(
'body' => json_encode($payload),
'headers' => array('Content-Type' => 'application/json')
));
error_log('Meta CAPI Response: ' . wp_remote_retrieve_body($response));
}
add_action('wpforms_process_complete', 'send_wpforms_to_meta_capi', 10, 3);
Critical: Always hash PII data (email, phone, names) when sending to CAPI. The code above handles this automatically.
Step 6: Testing & Verification
Test the Data Layer Push
- Fill out your WPForms form
- Open browser dev tools → Console
- Check for the “WPForms submission tracked” log message
- In GTM Preview mode, verify the
wpforms_submissionevent fires with correct data
Test Meta Pixel Events
- Go to Meta Events Manager → Test Events
- Enter your website URL
- Submit your form
- Verify the ‘Lead’ event appears with:
- Correct event_id
- User data parameters
- Custom parameters
Test CAPI Events
- In Events Manager → Test Events, look for server events (marked with server icon)
- Verify both pixel and CAPI events have matching event_ids
- Check the deduplication status - should show “Deduplicated” when both fire
Cross-Reference Numbers
Check these weekly to catch tracking degradation:
- WPForms Entries: WordPress Admin → WPForms → Entries
- Meta Conversions: Ads Manager → Columns → Conversions
- Acceptable variance: 5-15% difference is normal due to attribution windows and bot filtering
I typically see 85-95% match rate between form entries and Meta conversions when properly configured.
Troubleshooting
Problem: wpformsAjaxSubmitSuccess event not firing
→ Check if your form is using AJAX submission (WPForms Settings → Advanced → Enable AJAX). If disabled, use the wpformsFormSubmitted event instead, but note it fires before validation.
Problem: Data layer variables showing as undefined in GTM
→ The form field selectors in your JavaScript don’t match your actual form HTML. Inspect your form, find the correct input names, and update the selectors. WPForms uses format wpforms[fields][FIELD_ID].
Problem: Meta pixel firing but CAPI events not showing
→ Check your CAPI access token permissions and verify the pixel ID matches. Test with curl first: curl -X POST "https://graph.facebook.com/v18.0/PIXEL_ID/events?access_token=TOKEN" with a simple test payload.
Problem: Events showing as “Not Deduplicated” in Events Manager → The event_id values between pixel and CAPI don’t match. Ensure you’re using the same event_id generation logic and passing it to both tracking methods. The ID must be identical for deduplication to work.
Problem: High discrepancy between form entries and Meta conversions (>20%) → Check iOS Safari and users with ad blockers. If CAPI isn’t working, you’ll lose these conversions. Also verify your attribution window settings - Meta defaults to 1-day view, 7-day click.
Problem: Test events showing but live events not recording conversions → Remove the test_event_code parameter from production. Meta won’t count test events as actual conversions. Also check that your Meta Ads campaigns are optimizing for the correct conversion event.
What To Do Next
Now that your WPForms submissions are tracking in Meta Ads, consider these related setups:
- Track WPForms in Google Ads for cross-platform attribution
- Send WPForms data to HubSpot to close the loop with your CRM
- Set up GA4 conversion tracking for complete analytics coverage
Want me to audit your current tracking setup for free? I’ll identify what’s broken and what’s working in your conversion tracking. Get your free audit here.
This guide is part of the Meta Ads Conversion Tracking Hub — complete guides for tracking any conversion source in Meta Ads with pixel and CAPI setup.