Contact Form 7 + Meta Ads Conversion Tracking Setup

I see broken Contact Form 7 to Meta Ads tracking in about 35% of WordPress sites I audit. The main culprit? People try to track the form submit button click instead of listening for the actual wpcf7mailsent event that Contact Form 7 fires when the email is successfully sent. This results in counting failed submissions as conversions, which completely screws up your ROAS calculations.

The setup below uses Meta’s Conversions API (CAPI) alongside the pixel for maximum data coverage and proper event deduplication.

What You’ll Have Working By The End

Prerequisites

Step 1: Set Up the Contact Form 7 Event Listener

Contact Form 7 fires a wpcf7mailsent DOM event when a form is successfully submitted and the email is sent. We need to capture this and push it to the data layer.

Add this JavaScript to your theme’s functions.php file or as a custom HTML tag in GTM:

<script>
document.addEventListener('wpcf7mailsent', function(event) {
    // Generate unique event ID for deduplication
    var eventId = 'cf7_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    
    // Get form details
    var formId = event.detail.contactFormId;
    var formElement = event.target;
    var formTitle = formElement.querySelector('.wpcf7-form').getAttribute('data-title') || 'Contact Form ' + formId;
    
    // Push to data layer for GTM
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
        'event': 'cf7_form_success',
        'form_id': formId,
        'form_title': formTitle,
        'page_url': window.location.href,
        'event_id': eventId,
        'conversion_value': 0 // Set your lead value here
    });
    
    console.log('CF7 form submitted:', {
        formId: formId,
        eventId: eventId,
        formTitle: formTitle
    });
}, false);
</script>

Important: Don’t use wpcf7submit or button click events. The wpcf7mailsent event only fires when the form actually processes successfully, which is what you want for conversion tracking.

Step 2: Create the GTM Trigger

In GTM, create a new trigger:

  1. Trigger Type: Custom Event
  2. Event Name: cf7_form_success
  3. This trigger fires on: All Custom Events
  4. Name: CF7 - Form Success

Save the trigger.

Step 3: Create Data Layer Variables

Create these variables in GTM to capture the form data:

Variable 1: CF7 Form ID

Variable 2: CF7 Event ID

Variable 3: CF7 Form Title

Step 4: Create the Meta Pixel Tag

Create a new tag in GTM:

  1. Tag Type: Meta Pixel
  2. Pixel ID: Your Meta Pixel ID
  3. Event Type: Standard
  4. Event Name: Lead
  5. Object Properties:
    • content_name: {{CF7 - Form Title}}
    • content_category: contact_form
    • form_id: {{CF7 - Form ID}}
    • source: contact_form_7
  6. Event ID: {{CF7 - Event ID}}
  7. Triggering: CF7 - Form Success

Which event should you use? Use the standard “Lead” event rather than a custom conversion for better optimization. Meta’s algorithm works better with standard events, and you can create custom conversions from the Lead event data in Events Manager later.

Step 5: Set Up Meta Conversions API (CAPI)

For maximum tracking coverage, set up server-side tracking via CAPI. This requires server-side code. Here’s a PHP example:

<?php
// Add this to your theme's functions.php or a custom plugin

function send_cf7_to_meta_capi($contact_form, $abort, $submission) {
    if ($abort) return;
    
    $access_token = 'YOUR_CAPI_ACCESS_TOKEN';
    $pixel_id = 'YOUR_PIXEL_ID';
    
    // Get form data
    $form_id = $contact_form->id();
    $posted_data = $submission->get_posted_data();
    
    // Generate the same event ID format as client-side
    $event_id = 'cf7_' . time() . '_' . wp_generate_password(9, false);
    
    // Get user data for better matching
    $user_data = array(
        'client_ip_address' => $_SERVER['REMOTE_ADDR'],
        'client_user_agent' => $_SERVER['HTTP_USER_AGENT'],
        'fbc' => isset($_COOKIE['_fbc']) ? $_COOKIE['_fbc'] : null,
        'fbp' => isset($_COOKIE['_fbp']) ? $_COOKIE['_fbp'] : null
    );
    
    // Add email if captured in form
    if (!empty($posted_data['email'])) {
        $user_data['em'] = hash('sha256', strtolower(trim($posted_data['email'])));
    }
    
    // Prepare the event data
    $event_data = array(
        'event_name' => 'Lead',
        'event_time' => time(),
        'event_id' => $event_id,
        'action_source' => 'website',
        'event_source_url' => home_url($_SERVER['REQUEST_URI']),
        'user_data' => array_filter($user_data),
        'custom_data' => array(
            'content_name' => get_the_title() . ' - Contact Form ' . $form_id,
            'content_category' => 'contact_form',
            'form_id' => $form_id,
            'source' => 'contact_form_7'
        )
    );
    
    // Send to Meta CAPI
    $capi_data = array(
        'data' => array($event_data)
    );
    
    $args = array(
        'body' => json_encode($capi_data),
        'headers' => array(
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $access_token
        ),
        'timeout' => 15
    );
    
    wp_remote_post(
        "https://graph.facebook.com/v18.0/{$pixel_id}/events",
        $args
    );
}

// Hook into Contact Form 7 submission
add_action('wpcf7_mail_sent', 'send_cf7_to_meta_capi', 10, 3);
?>

Event deduplication is critical. Both the client-side pixel and CAPI must use the same event_id to prevent double-counting conversions.

Step 6: Testing & Verification

Test in Meta Events Manager

  1. Go to Events ManagerTest Events
  2. Enter your website URL and click Open Website
  3. Submit a Contact Form 7 form
  4. Check the Test Events tab for:
    • Lead event received via pixel
    • Lead event received via CAPI (if implemented)
    • Same event_id on both events
    • Proper deduplication (should show as 1 event, not 2)

Verify GTM Data Layer

Open browser dev tools, submit a form, and check the console. You should see:

CF7 form submitted: {
  formId: 123,
  eventId: "cf7_1703123456_abc123def",
  formTitle: "Contact Form"
}

Cross-Check Conversion Counts

Compare these numbers weekly:

Troubleshooting

Problem: Events show in Test Events but not in Ads Manager conversions
Solution: Check if you’ve created a custom conversion for the Lead event or are using a custom event name that doesn’t match your campaign optimization settings.

Problem: Getting duplicate events (pixel + CAPI showing as 2 conversions)
Solution: Ensure both client-side and server-side code are using identical event_id values. The format and generation method must match exactly.

Problem: Form submissions not triggering the data layer push
Solution: Check if other plugins are interfering with the wpcf7mailsent event. Try adding the event listener with setTimeout to ensure it runs after other scripts: setTimeout(function() { /* your code here */ }, 100);

Problem: CAPI events showing “No Match” in Events Manager
Solution: Improve user data matching by capturing more identifiers like phone number (hashed) or ensuring the email field is properly captured and hashed with SHA256.

Problem: Events firing on form submission but before validation
Solution: You’re probably listening for wpcf7submit instead of wpcf7mailsent. Only wpcf7mailsent fires after successful validation and email sending.

Problem: Meta showing much lower conversion counts than form submissions
Solution: This usually indicates the pixel isn’t firing properly. Check for JavaScript errors, ad blocker interference, or that your Meta Pixel ID is correct in GTM.

What To Do Next

Now that your Contact Form 7 submissions are tracking properly in Meta Ads, consider these next steps:

This guide is part of the Meta Ads Conversion Tracking Hub — complete guides for tracking any conversion type in Meta Ads.