Tracking inside embeds

MarketingIT / Technical

When you embed the Preb booking widget on your own website, the widget runs inside a frame — so your page's own Google Analytics, Tag Manager, or pixel can't see what happens inside it directly. Instead, Preb sends events up to your page, and you listen for them with a small window.Preb.on(...) snippet.

This is for the embedded widget on your site

If you use Preb's own hosted booking pages (not an embed), you don't need this — configure Meta, Google Ads, GA4, or GTM and Preb handles tracking on those pages for you.

The no-code way: automatic forwarding

The snippet from your event type's Embed tab ships with data-preb-analytics="auto" switched on: Preb pushes every event straight into the tags your page already has — Google Tag Manager (dataLayer), GA4 (gtag) and Meta Pixel (fbq). Nothing is loaded or created; a page without these tags is unaffected. Untick the option in the Embed tab if you want nothing forwarded.

<div
  data-preb-link="acme/intro-call"
  data-preb-analytics="auto"
></div>
<script src="https://app.preb.co/embed.js" async></script>

Events arrive under their Preb names (preb_booking_completed, preb_form_started, …) with the payloads listed below. In Tag Manager, trigger on a Custom Event named preb_booking_completed; in GA4 the events appear as custom events; in Meta as custom events you can build audiences on.

Consent is respected the same way as everywhere else: funnel events only leave the widget for consented visitors, and preb_booking_completed reaches GA4 and Meta only when consent was granted (it always reaches the dataLayer, where Tag Manager applies your own consent rules). The Embed tab has a checkbox that adds the attribute for you.

Listen for events (custom code)

Place this before your embed snippet. The little stub queues your subscriptions until the embed script loads, so nothing is missed:

<!-- Place this before your embed snippet -->
<script>
  window.Preb = window.Preb || {
    _q: [],
    on: function (a, b) { this._q.push([a, b]); }
  };

  // A completed booking — the conversion.
  window.Preb.on('bookingSuccessful', function (data) {
    // data: { uid, title, startTime, endTime, location,
    //         eventTypeId, eventTypeSlug, eventName }
  });

  // The same conversion in the exact shape Preb pushes to GA4 / GTM on hosted
  // pages — forward it to your page's own tag so hosted and embedded bookings
  // land in one report:
  window.Preb.on('preb_booking_completed', function (data) {
    if (window.gtag) window.gtag('event', 'preb_booking_completed', data);
    if (window.dataLayer) window.dataLayer.push({ event: 'preb_booking_completed', ...data });
  });

  // Optional: funnel step events for drop-off analysis.
  window.Preb.on('preb_event_type_viewed', function () { /* … */ });
  window.Preb.on('preb_form_started',      function () { /* … */ });
  window.Preb.on('preb_day_selected',      function () { /* … */ });
  window.Preb.on('preb_time_selected',     function () { /* … */ });
</script>

You can copy a ready-made version of this from your event type's Embed tab.

The events you can listen for

EventFires whenPayload
bookingSuccessfulA booking is confirmed{ uid, title, startTime, endTime, location, eventTypeId, eventTypeSlug, eventName }
preb_booking_completedSame moment — the conversion, in the shape Preb pushes to GA4/GTM{ preb_booking_uid, preb_contact_email, event_type_id, event_type_slug, event_name, marketing_consent }
preb_event_type_viewedThe widget loadsevent type
preb_form_startedThe visitor starts the formevent type
preb_day_selectedA day is pickedevent type + date
preb_time_selectedA time is pickedevent type + time

Every event identifies the event type being booked, so a page that embeds more than one booking link can tell them apart:

window.Preb.on('preb_form_started', function (data) {
  // data.event_type_slug → 'discovery-call'
  // data.event_name      → 'Discovery Call'
  // data.event_type_id   → Preb's internal ID
});

Wire these into gtag, dataLayer.push, fbq, or any analytics you run on your page.

Funnel events respect consent

The preb_* funnel events are only sent up to your page for visitors who accepted marketing cookies — see Consent inside embeds for how the widget learns that. bookingSuccessful and preb_booking_completed always fire so your booking confirmation logic runs regardless; preb_booking_completed carries marketing_consent so you can decide what to attach. Don't attach ad tracking that your own consent tooling hasn't cleared.

Embedded on your site, the widget never shows a cookie banner of its own — your page owns consent, and a second banner inside a booking form would be wrong for your visitors. Instead, you hand the decision to the widget:

<!-- From your cookie banner's "accept" handler: -->
<script>
  window.Preb.consent('granted');   // or 'denied' when a visitor withdraws
</script>

Preb.consent() applies to every Preb widget on the page, including ones that open later (a popup), and updates a widget that is already open. It works before embed.js has loaded as long as you include the small stub at the top of this page.

If your site has no cookie banner at all — for example a landing page that sets no non-essential cookies — you can declare consent on the element instead:

<div data-preb-link="acme/intro-call" data-preb-consent="granted"></div>

Until the widget receives a granted decision it runs with consent denied: no Meta Pixel, GTM or GA4 script is loaded inside the widget, no preb_* funnel events are sent, and the booking is reported to Meta and Google server-side as unconsented — exactly as for a hosted-page visitor who declined.

Your consent decision, your responsibility

Calling Preb.consent('granted') tells Preb that this visitor agreed to marketing cookies on your site. Only call it after a real opt-in from your own consent tooling. The event-type setting Hide cookie banner does not affect embeds — inside an embed the banner is never shown, regardless of that setting.

Verify your setup

Open your page with the embed, book a test appointment, and watch your browser's developer Console — a quick console.log inside each handler confirms the events arrive. Then check they land in your analytics (GA4 Realtime, GTM Preview, or Meta Pixel Helper).

Attribution in embeds

The inline and popup embeds automatically forward ad click IDs and UTM tags (gclid, fbclid, utm_*) from your page's URL into the widget, so campaign attribution keeps working. They also pass along your page's address so Meta receives your landing page — not the widget's own address — as the source of the conversion. If instead you link out to a hosted booking page from a button, add the forwarding snippet from the Embed tab to your landing page. See Attribution & UTM tracking.