Form Events & dataLayer
The widget emits DOM CustomEvents and pushes to window.dataLayer (for Google Tag Manager) so you can track form views, field interactions, bookings, and submissions in your analytics stack — without touching the form internals.
Event list
Section titled “Event list”| Event | Detail | DOM | dataLayer | Telemetry |
|---|---|---|---|---|
rl:form:view | formId, studioId? | ✓ | ✓ | ✓ |
rl:form:prefill | formId, studioId?, prefilledFieldIds | ✓ | ✓ | ✓ |
rl:form:step | formId, studioId?, step | ✓ | ✓ | ✓ |
rl:form:field:change | formId, fieldId, fieldName? | ✓ | — | — |
rl:form:field:blur | formId, fieldId, fieldName? | ✓ | — | ✓ |
rl:form:submit:start | formId, studioId? | ✓ | ✓ | ✓ |
rl:form:submit:success | formId, submissionId, formData, bookingSlot? | ✓ | ✓ | ✓ |
rl:form:submit:error | formId, errorCode, error? | ✓ | ✓ | ✓ |
rl:form:booking:type | formId, fieldId, fieldName?, appointmentTypeId | ✓ | ✓ | ✓ |
rl:form:booking:month | formId, fieldId, fieldName?, direction | ✓ | ✓ | ✓ |
rl:form:booking:date | formId, fieldId, fieldName?, dateKey | ✓ | ✓ | ✓ |
rl:form:booking:slot | formId, fieldId, fieldName?, slotKey | ✓ | ✓ | ✓ |
rl:form:captcha:load | formId, provider | ✓ | ✓ | ✓ |
rl:form:captcha:success | formId, provider | ✓ | ✓ | ✓ |
rl:form:captcha:error | formId, provider | ✓ | ✓ | ✓ |
rl:form:captcha:reset | formId, provider | ✓ | ✓ | ✓ |
Detail shape
Section titled “Detail shape”All events share this superset of detail fields:
interface EventDetail { formId: string; studioId?: string; step?: number; fieldId?: string; fieldName?: string; // set only when the field has a non-empty `name` — fall back to fieldId when absent submissionId?: string; error?: string; errorCode?: 'validation' | 'captcha' | 'network' | 'server' | 'unknown'; durationMs?: number; // Booking calendar context appointmentTypeId?: string; direction?: 'prev' | 'next'; dateKey?: string; slotKey?: string; // Captcha context provider?: string; // DOM/dataLayer only — never sent to telemetry formData?: Record<string, string | string[]>; bookingSlot?: { appointmentTypeId, calendarId, resourceId?, startDateTime, endDateTime }; prefilledFieldIds?: string[];}Listening for events
Section titled “Listening for events”document.addEventListener('rl:form:submit:success', (e) => { console.log('Form submitted:', e.detail.submissionId); console.log('Data:', e.detail.formData);});Listeners on document see events from every form on the page. Filter by e.detail.formId if you have multiple.
dataLayer
Section titled “dataLayer”The widget pushes to window.dataLayer for every event in the list above (except the two excluded). Each push has the shape:
{ event: '<event-name>', ...detail }So a successful submission lands as:
{ event: 'rl:form:submit:success', formId: '...', submissionId: '...', formData: { email: '...', firstName: '...', ... }, bookingSlot: { ... }}GTM setup
Section titled “GTM setup”- Create a Custom Event trigger for
rl:form:submit:success(or whichever event you want). - Build a tag (Meta Pixel, Google Ads, etc.) that fires on the trigger.
- Map
{{eventModel.formId}},{{eventModel.submissionId}}, etc. into your tag’s parameters via Data Layer Variables.
For field-level triggers (e.g., “track when user fills email”), key on eventModel.fieldName rather than fieldId — see the tip above.
Ad pixel integration (Meta CAPI, Google Ads)
Section titled “Ad pixel integration (Meta CAPI, Google Ads)”For conversion tracking with deduplication:
document.addEventListener('rl:form:submit:success', (e) => { fbq('track', 'Lead', { eventID: e.detail.submissionId, // dedup key for Conversion API content_name: e.detail.formId, });});Phone numbers in formData are E.164-normalized — see Field Types → tel.
Telemetry beacon
Section titled “Telemetry beacon”The widget batches a subset of events into a POST /public/forms/:id/telemetry beacon for funnel analytics (see Public API → telemetry). The beacon is best-effort — drops on 429 or network failure — and contains no PII: formData, bookingSlot, appointmentTypeId, slotKey are stripped client-side before queueing.
Related
Section titled “Related”- Public API → telemetry — the endpoint behind the beacon.
- Webhooks — server-side counterpart to
submit:success. SamesubmissionIdfor cross-channel dedup. - Embedding → Stable Field Names — where
fieldNamecomes from. - Prefill —
rl:form:prefillfires when prefill is applied at mount.