Calendly + Meta Ads Conversion Tracking Setup

I see this setup broken in about 45% of the Meta ad accounts I audit. Usually it’s because they’re relying purely on the Meta Pixel without server-side backup, or they’ve got the Calendly event listener configured wrong and are missing 20-30% of bookings. The postMessage event from embedded Calendly widgets is finicky, and if you’re not handling the redirect method properly, you’re flying blind on conversion data.

What You’ll Have Working By The End

Prerequisites

Step 1: Set Up Calendly Event Detection

The key is catching the calendly.event_scheduled postMessage when someone books through an embedded widget, plus tracking redirect completions for standalone booking pages.

First, add this JavaScript to your site (or via GTM Custom HTML tag):

// Calendly embedded widget event listener
window.addEventListener('message', function(e) {
  if (e.origin !== 'https://calendly.com') {
    return;
  }
  
  if (e.data.event && e.data.event === 'calendly.event_scheduled') {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      'event': 'calendly_booking_completed',
      'booking_uri': e.data.payload.event.uri,
      'invitee_name': e.data.payload.invitee.name,
      'invitee_email': e.data.payload.invitee.email,
      'event_type': e.data.payload.event_type.name
    });
  }
});

// Redirect-based tracking for standalone Calendly pages
if (window.location.href.includes('calendly.com/scheduled_events/')) {
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    'event': 'calendly_booking_completed'
  });
}

Step 2: Configure GTM Trigger

Create a Custom Event trigger in GTM:

I also set up a Page View trigger for the redirect method:

Step 3: Set Up Meta Pixel Tag in GTM

Create a new Meta Pixel tag:

The Event ID is crucial for deduplication between pixel and CAPI. I use this custom variable:

function() {
  return 'calendly_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}

Step 4: Implement Meta Conversions API (CAPI)

This is where most setups fall apart. You need server-side tracking to capture the 15-25% of users who block the pixel.

If you’re using Calendly webhooks (recommended), set up a webhook endpoint in Calendly that points to your server. Here’s the payload structure you’ll receive:

{
  "event": "invitee.created",
  "payload": {
    "event_type": {
      "name": "30 Minute Meeting"
    },
    "invitee": {
      "email": "user@example.com",
      "name": "John Doe"
    }
  }
}

Your server endpoint needs to send this to Meta CAPI:

const metaPayload = {
  "data": [
    {
      "event_name": "Lead",
      "event_time": Math.floor(Date.now() / 1000),
      "event_id": generateEventId(), // Same format as GTM
      "user_data": {
        "em": hashEmail(payload.invitee.email),
        "fn": hashName(payload.invitee.name.split(' ')[0]),
        "ln": hashName(payload.invitee.name.split(' ')[1])
      },
      "custom_data": {
        "content_name": payload.event_type.name,
        "content_category": "booking",
        "value": 50.00,
        "currency": "USD"
      },
      "event_source_url": "https://yoursite.com",
      "action_source": "website"
    }
  ]
};

// Send to Meta CAPI endpoint
fetch(`https://graph.facebook.com/v18.0/${pixelId}/events?access_token=${accessToken}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(metaPayload)
});

Which should you use? Always implement both. The pixel catches immediate conversions, CAPI catches the blocked ones. With proper event_id deduplication, Meta will merge them automatically.

Step 5: Testing & Verification

Test the Setup

  1. Go through a complete Calendly booking on your site
  2. Check GTM Preview mode — you should see the calendly_booking_completed event firing
  3. Verify the Meta Pixel tag fires with the Lead event
  4. In Meta Events Manager, go to Test Events and confirm the Lead event appears within 2-3 minutes

Verify Recording

Cross-Check Numbers

Your Calendly “Scheduled Events” count should match your Meta “Lead” conversions within 5-15%. Higher variance usually means:

Troubleshooting

Problem: GTM shows the event firing but no Lead events in Meta Events Manager
Check your Meta Pixel ID in the GTM tag. I see this wrong in about 30% of setups I audit. Also verify your pixel isn’t getting blocked by content blockers in your test browser.

Problem: Getting duplicate conversions (pixel + CAPI both counting)
Your event_id values aren’t matching between client and server-side. Make sure you’re using the same ID generation method and the server receives the ID from the client-side event.

Problem: Calendly event listener not firing on embedded widgets
The postMessage origin check is case-sensitive. Also, some Calendly embedding methods don’t fire the standard event. Try adding a backup method that watches for URL changes to calendly.com/thank_you pages.

Problem: CAPI webhook returns 400 errors
Usually it’s the user_data hashing. Email and name fields must be lowercased and SHA256 hashed. Also check that event_time is a Unix timestamp, not milliseconds.

Problem: Numbers are way off (30%+ variance)
You’re probably missing one of the booking methods. Check if you have both embedded widgets AND redirect-based bookings. Also verify your webhook URL is receiving all Calendly event types.

Problem: Events showing as “Not Matched” in Events Manager
The user_data parameters aren’t matching Meta’s user profiles. Try adding more matching parameters like phone number (ph) or click ID (fbc) if available from your ad traffic.

What To Do Next

Once you’ve got Calendly tracking dialed in, here are the logical next steps:

This guide is part of the Meta Ads Conversion Tracking Hub — covering pixel setup, CAPI implementation, iOS 14.5+ tracking, and platform-specific form integrations.