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

Prerequisites

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:

  1. Trigger Type: Custom Event
  2. Event name: wpforms_submission
  3. 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:

Step 4: Configure Meta Pixel Tag

Create a new Meta Pixel tag in GTM:

  1. Tag Type: Meta Pixel
  2. Track Type: Track Custom Events
  3. Event Name: Lead (use standard event for better optimization)
  4. Event Parameters:
    content_name: {{DLV - Form Title}}
    content_category: lead_form
    value: {{DLV - Conversion Value}}
    currency: USD
  5. 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}}
  6. 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:

  1. Tag Type: Meta Conversions API
  2. Event Name: Lead
  3. Event Parameters: Same as pixel tag
  4. User Data Parameters:
    email: {{DLV - User Email}}
    first_name: {{DLV - User First Name}}
    last_name: {{DLV - User Last Name}}
    phone: {{DLV - User Phone}}
  5. Event ID: {{DLV - Event ID}} (critical for deduplication)
  6. 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

  1. Fill out your WPForms form
  2. Open browser dev tools → Console
  3. Check for the “WPForms submission tracked” log message
  4. In GTM Preview mode, verify the wpforms_submission event fires with correct data

Test Meta Pixel Events

  1. Go to Meta Events Manager → Test Events
  2. Enter your website URL
  3. Submit your form
  4. Verify the ‘Lead’ event appears with:
    • Correct event_id
    • User data parameters
    • Custom parameters

Test CAPI Events

  1. In Events Manager → Test Events, look for server events (marked with server icon)
  2. Verify both pixel and CAPI events have matching event_ids
  3. Check the deduplication status - should show “Deduplicated” when both fire

Cross-Reference Numbers

Check these weekly to catch tracking degradation:

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:

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.