Calendly GTM Event Listener
Track Calendly booking widget interactions in GTM. Monitor profile page views, event type views, date/time selections, and meeting scheduled events. Fire GA4 and Google Ads conversions on confirmed bookings.
Event fired
calendlyKey variable
calendly_eventCalendly
Overview
Calendly is the most popular scheduling tool for sales, support, and consulting teams. Its embedded widget communicates via window.postMessage. This listener captures all Calendly scheduling events, from page views to confirmed bookings, enabling accurate conversion tracking.
Event fired: calendly (all events use one event name)
Variable: calendly_event, describes the specific interaction type
Why Use This Listener
A Calendly booking is one of the highest-intent conversion events in a B2B funnel. Without this listener, you cannot:
- Track which marketing channels drive demo bookings
- Fire Google Ads conversion tags on scheduled meetings
- Build Google/Meta audiences from people who booked meetings
- Calculate demo-request-to-booking rates in GA4
Calendly Event Types
| calendly_event | Description |
|---|---|
calendly.profile_page_viewed | Booking page loads |
calendly.event_type_viewed | User views specific event type |
calendly.date_and_time_selected | User picks a time slot |
calendly.event_scheduled | Booking confirmed ← primary conversion |
How It Works
Calendly sends postMessage events from its embedded iframe as users interact with the booking widget. The listener uses window.addEventListener('message', ...) to intercept these.
sequenceDiagram
participant V as Visitor
participant C as Calendly Widget
participant L as Listener
participant DL as dataLayer
participant GTM as GTM
V->>C: Views booking page
C->>L: postMessage: profile_page_viewed
L->>DL: push {event: "calendly", calendly_event: "...profile_page_viewed"}
V->>C: Selects time slot
C->>L: postMessage: date_and_time_selected
L->>DL: push {event: "calendly", calendly_event: "...date_and_time_selected"}
V->>C: Confirms booking
C->>L: postMessage: event_scheduled
L->>DL: push {event: "calendly", calendly_event: "...event_scheduled"}
DL->>GTM: Fires GA4 + Google Ads conversionGTM Setup Guide
Step 1: Create Custom HTML Tag
- GTM → Tags → Custom HTML
- Paste the code below
- Trigger: All Pages (Pageview)
Step 2: Create Triggers
| Trigger Name | Event Name | Condition |
|---|---|---|
| CE – Calendly All | calendly | — |
| CE – Calendly Booked | calendly | calendly_event contains event_scheduled |
| CE – Calendly Time Selected | calendly | calendly_event contains date_and_time_selected |
Step 3: Create Variable
| Variable Name | DL Key |
|---|---|
| DLV – Calendly Event | calendly_event |
Step 4: Attach Tags
CE – Calendly Booked→ GA4 eventbook_appointment, Google Ads conversion, MetaScheduleeventCE – Calendly Time Selected→ GA4 engagement event
Installation
<!-- GTM Custom HTML Tag: Calendly Listener -->
<!-- Trigger: All Pages (Pageview) -->
<script>
function isCalendlyEvent(e) {
return e.origin === 'https://calendly.com' && e.data.event && e.data.event.indexOf('calendly.') === 0;
}
window.addEventListener('message', function(e) {
if (isCalendlyEvent(e)) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'calendly',
'calendly_event': e.data.event,
'calendly_event_type_name': e.data.payload && e.data.payload.event_type && e.data.payload.event_type.name,
'calendly_event_type_duration': e.data.payload && e.data.payload.event_type && e.data.payload.event_type.duration,
'calendly_invitee_email': e.data.payload && e.data.payload.invitee && e.data.payload.invitee.email,
'calendly_invitee_name': e.data.payload && e.data.payload.invitee && e.data.payload.invitee.name,
'calendly_event_start_time': e.data.payload && e.data.payload.event && e.data.payload.event.start_time,
'calendly_tracking_utm_source': e.data.payload && e.data.payload.tracking && e.data.payload.tracking.utm_source,
'calendly_tracking_utm_medium': e.data.payload && e.data.payload.tracking && e.data.payload.tracking.utm_medium,
'calendly_tracking_utm_campaign': e.data.payload && e.data.payload.tracking && e.data.payload.tracking.utm_campaign
});
}
});
</script>Data Layer Output
Event Scheduled (Booking Confirmed)
{
"event": "calendly",
"calendly_event": "calendly.event_scheduled",
"calendly_event_type_name": "30-Minute Demo",
"calendly_event_type_duration": 30,
"calendly_invitee_email": "jane@acmecorp.com",
"calendly_invitee_name": "Jane Smith",
"calendly_event_start_time": "2024-02-15T14:00:00Z",
"calendly_tracking_utm_source": "google",
"calendly_tracking_utm_medium": "cpc",
"calendly_tracking_utm_campaign": "brand-terms"
}Date/Time Selected
{
"event": "calendly",
"calendly_event": "calendly.date_and_time_selected",
"calendly_event_type_name": "30-Minute Demo"
}Variables to Capture
| Variable Name | DL Key | Example |
|---|---|---|
| DLV – Calendly Event | calendly_event | "calendly.event_scheduled" |
| DLV – Calendly Event Type | calendly_event_type_name | "30-Minute Demo" |
| DLV – Calendly Invitee Email | calendly_invitee_email | "jane@acmecorp.com" |
| DLV – Calendly Invitee Name | calendly_invitee_name | "Jane Smith" |
| DLV – Calendly UTM Source | calendly_tracking_utm_source | "google" |
| DLV – Calendly Start Time | calendly_event_start_time | "2024-02-15T14:00:00Z" |
GA4 Mapping Recommendations
| GA4 Event | Trigger | Parameters |
|---|---|---|
book_appointment | Calendly Booked | event_type, email, duration |
select_content | Date/Time Selected | content_type: "time_slot" |
view_item | Event Type Viewed | item_name: event type |
Enhanced Conversions setup:
- Use
calendly_invitee_emailas the user email in Google's User-Provided Data variable
Debugging
GTM Preview Mode
- Embed a Calendly widget on your site
- Open GTM Preview mode
- Go through the booking flow
- Check for
calendlyevents at each step - Verify
calendly_event_scheduledfires on confirmation
Common Issues
| Problem | Cause | Fix |
|---|---|---|
| No events | Origin check fails | Verify Calendly loads from calendly.com |
event_scheduled not firing | Using redirect (not embed) | This listener is for embedded widgets only |
| Missing payload data | Older Calendly API version | payload is only in v2 postMessage format |
Redirect vs. Embed
For Calendly redirect pages (user goes to calendly.com/yourname), use GTM on the Calendly thank you page URL parameter instead of this listener.
Best Practices
- Use Calendly's UTM passthrough, Calendly passes UTMs in the
trackingpayload. Capture all UTM parameters to attribute bookings to campaigns - Hash the email for Enhanced Conversions,
calendly_invitee_emailis perfect for Google's Enhanced Conversions - Per-event-type triggers, Create different conversion actions for "Demo" vs. "Support" vs. "Onboarding" calls
- Set up the booking funnel in GA4: Profile Viewed → Event Type Viewed → Time Selected → Booked
Performance Considerations
- The
isCalendlyEventorigin check prevents performance issues from processing all postMessages - Zero polling, pure event-driven architecture
Related Listeners
- OnSched
- Vimeo, Often paired with demo videos
- Drift Chat, Meeting booking from chat
Example Business Scenarios
Scenario: SaaS Sales Funnel
A SaaS company embeds Calendly for "Book a Demo" on their pricing page. They track:
calendly.profile_page_viewed→ Demo intent (fire MetaViewContent)calendly.date_and_time_selected→ High intent (fire MetaInitiateCheckout)calendly.event_scheduled→ Conversion (fire Google Ads, MetaSchedule, GA4book_appointment)
They also capture calendly_tracking_utm_campaign to see which Google Ads campaigns drive the most demos.
FAQ
Q: Does this work with Calendly popup widgets? A: Yes, popup embeds use the same postMessage API.
Q: Does it work for multiple Calendly widgets on the same page? A: Yes, the listener captures all Calendly postMessages on the page.
Q: Can I capture the meeting notes the invitee enters? A: No, the payload only includes basic invitee info and event details, not form answers. Those are in the Calendly webhook.
Q: Does this work on Calendly's routing forms?
A: Routing form events may use different event names. Test in Preview mode and inspect the e.data.event value.