Integrations

Conversion tracking & attribution

Your ad attribution survives the embed — conversions fire in your own analytics, and the click data is saved on the booking.

Why this matters

Embedded schedulers normally break ad attribution. The booking happens inside an iframe served from another domain, so the conversion lands in the scheduler's analytics session — not yours — and your ad platforms report the booking as "direct" traffic. The campaign that actually drove the appointment never gets credit.

Cartoply solves this two ways, and both are automatic when you use the embed script: conversion events fire on your page in your analytics session, and the visitor's ad-click attribution is captured and stored on the booking itself.

Conversions fire in your analytics

The embed script runs on your own page, inside your visitor's normal analytics session. When a booking completes inside the embed, the script automatically forwards the conversion to whatever tracking you already have installed:

  • Google Tag Manager — pushes a cartoply_booking_confirmed event to dataLayer.
  • GA4 (gtag) — fires a cartoply_booking_confirmed custom event and the standard generate_lead event.
  • Meta Pixel — fires a CartoplyBookingConfirmed custom event and the standard Schedule event.
  • Everything else — a DOM cartoply:booking-confirmed CustomEvent is always dispatched on window for custom setups (see below).

Because these events fire in the visitor's session on your domain, the ad click that brought them to your site stays attached to the conversion natively — no cross-domain measurement setup, no linker parameters, nothing to configure.

GA4 & Google Ads how-to

In GA4, go to Admin → Events and mark generate_lead (or cartoply_booking_confirmed, if you want a Cartoply-only signal) as a Key Event. Google Ads can then import it as a conversion action. Since the event fires in the visitor's own session on your domain, the original ad click (gclid) is preserved automatically — campaigns get full credit for the bookings they generate.

Google Tag Manager how-to

Create a Custom Event trigger with the event name cartoply_booking_confirmed and attach it to whatever tags you want to fire on a booking. These extra dataLayer keys are available for use in variables:

  • cartoply_event_name — the name of the booked event type.
  • cartoply_start_time — the appointment start time.
  • cartoply_requestedtrue if the booking was held for host approval (see below).

Custom integrations

For anything else — your own analytics, a CRM tag, closing the popup yourself — listen for the DOM event the embed always dispatches. The booking details are on e.detail:

window.addEventListener('cartoply:booking-confirmed', (e) => {
  // e.detail = { type, event, start, requested }
  console.log('Booked:', e.detail.event, 'at', e.detail.start);
});

Attribution is saved on the booking

Separately from firing conversions, the embed script reads campaign parameters from your page's URL (where the ad landed) and forwards them into the booking flow. On each booking, Cartoply stores:

  • utmSource, utmMedium, utmCampaign, utmTerm, utmContent — from the standard utm_* parameters.
  • gclid (Google Ads), fbclid (Meta), msclkid (Microsoft Ads) — ad click IDs.
  • referrer — the referring page, and page — the URL of the page the embed was on.

Attribution is first-touch and persists across your site: the parameters are captured on the page the visitor lands on and remembered for the rest of their browser session, so someone who arrives from an ad, browses to your contact page, and books there is still attributed to the ad. Direct visits to a Cartoply booking page (no embed) with utm_* or click-ID parameters on the URL are captured too.

The stored attribution rides along as an attribution object in Zapier webhook payloads (booking.created, booking.requested, and the rest) — use it to sync lead source into your CRM, or to upload offline conversions to Google Ads by gclid when a booking later turns into revenue.

Bookings held for approval

If the event type uses manual approval (pre-qualification), the conversion events still fire when the guest submits — but with cartoply_requested: true (and requested: true on the DOM event payload), meaning the booking is held for host approval and not yet confirmed. Decide whether to count these as conversions in your setup: count them if you optimize for lead volume, or filter on cartoply_requested being false if you only want confirmed appointments.