How to Track Appointment Bookings in GA4
Measure saved appointment bookings in GA4 with a success event, safe parameters, key-event reporting and tests for failed or repeated reservations.
Track appointment bookings in GA4 by listening for a successfully saved reservation, pushing a small data-layer event, and sending it through a GA4 Event tag. The Niwa website scheduler recipe below counts a confirmed appointment after the booking response succeeds. It includes duplicate protection within the page and checks for failed reservations.
With Niwa’s booking workflow, customers can check availability and reserve an appointment on the website or directly in a WhatsApp conversation. Niwa uses the website’s business context to complete the booking. The recipe below measures the website scheduler; a reservation completed in WhatsApp does not itself trigger its browser event.
Use Niwa’s saved-booking event
The website scheduler in Niwa AI version 0.13.1061 emits niwa:scheduler:booked on document. Its detail.appointment includes the saved appointment ID and status. The booking service inserts and commits the reservation before returning success; the browser dispatches this event after that successful response.
This setup targets that scheduler contract. Check that your installed scheduler exposes the same event before installing the listener, particularly after changing versions. It does not create an automatic GA4 export or cover another booking plugin.
Count confirmed appointments for this recipe. If your separate workflow saves a pending request for staff approval, measure that as a request rather than calling it a confirmed reservation. A paid appointment also needs its payment outcome measured through the payment system.
Register a minimal completion listener
Use your existing GTM web container and Google tag; complete the GA4 setup on WordPress first if these are missing. Create a Custom HTML tag named Listener – Niwa booking. Place this JavaScript inside an opening and closing script element, trigger it on DOM Ready for scheduler pages, and select Once per page under Advanced Settings, Tag firing options. Register it once before a customer can complete a booking.
(function () {
var seen = new Set();
document.addEventListener('niwa:scheduler:booked', function (event) {
var appointment = event.detail && event.detail.appointment;
if (!appointment || !appointment.id || appointment.status !== 'confirmed') return;
var id = String(appointment.id);
if (seen.has(id)) return;
seen.add(id);
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'niwa_appointment_success',
booking_channel: 'website'
});
});
})();
The listener accepts only a result with an appointment ID and the technical status confirmed. It sends event: niwa_appointment_success and booking_channel: website. It neither reads translated button labels nor examines customer messages.
The appointment ID stays inside the page’s private seen set and is not sent to GTM or GA4. Do not push the entire event detail: it also carries contact information and other booking context. The Google data-layer guide shows how an event and permitted parameters travel together.
This duplicate protection lasts for the current page only. It stops a repeated completion response for the same ID from producing another event there. It does not provide server-wide or cross-tab deduplication. A refresh alone does not invoke this listener, but integrations that replay old bookings across page loads need their own durable duplicate control.
Configure the GTM event tag
Create a Data Layer Variable named DLV – booking_channel, using booking_channel as its variable name and Version 2. Follow Google’s variable documentation if you need to inspect its value during Preview.
Create a Custom Event trigger with Event name niwa_appointment_success, regular-expression matching off, and All Custom Events selected. Call it Niwa saved appointment. This matches the exact data-layer event, as described in the Custom Event trigger guide.
Add a Google Analytics: GA4 Event tag. Enter the existing web stream’s G- Measurement ID, set Event Name to appointment_booked, and add booking_channel with value {{DLV - booking_channel}}. Attach Niwa saved appointment as the trigger and save. Google’s event-tag instructions explain these fields.
appointment_booked is the custom GA4 name chosen for this setup. Do not create a second Google tag or retain an older booking tag sending the same outcome. GA4 does not automatically deduplicate this custom event because a booking ID exists in your application.
Verify a reservation from schedule to DebugView
Open GTM Preview and connect Tag Assistant to the scheduler page. Use an authorized test booking with analytics consent granted. First check the appointment in Niwa’s schedule; then select niwa_appointment_success in Tag Assistant and verify that the GA4 tag fired once with booking_channel equal to website.
Open GA4 Admin, Data display, DebugView. Select your test device, find appointment_booked and inspect its parameters. Google’s DebugView instructions explain this view. Confirm that no name, phone, email, service details or appointment time entered the analytics payload.
Refresh the page and reopen the scheduler without completing a new reservation. Neither action should count a booking. Test a safely controlled unavailable slot and missing required fields: unsuccessful attempts should produce no completion event. A second real reservation with a different ID should count once.
On a staging test page, you can also replay the same completion event twice to check the listener’s in-page duplicate protection. A synthetic event tests the wiring only; it does not prove that a reservation was saved. Keep that test separate from the real schedule check.
Respect consent and any domain transition
The consent platform must establish Google consent state before the GA4 tag runs. This listener does not grant consent. Test the site’s acceptance and refusal paths; account for the difference between a basic implementation that blocks GA4 until permission and deliberately configured advanced Consent Mode.
Keep names, email addresses, phone numbers, appointment notes and sensitive service categories out of Analytics. Google’s privacy guidance also covers personal information in URLs.
For Niwa’s same-site scheduler, the completion happens on the website. If your business instead sends customers to a separate booking domain, use that provider’s supported completion integration and check cross-domain measurement. An outbound click alone remains a click. Campaign parameters on a WhatsApp-to-website link identify that arrival, not every conversation or its eventual outcome.
Report confirmed bookings alongside operational records
Once the event appears, mark appointment_booked as a key event if it represents an important outcome. Google’s key-event guide explains this setting. Register booking_channel as an event-scoped custom dimension if you need it in reports.
Compare this event with landing pages and session traffic sources. Keep cancellations, rescheduling, attendance and payments in their appropriate operational views. A confirmed appointment can later change, and analytics collection can be blocked, so the schedule remains your booking record.
Publish the tested GTM version with a note describing the scheduler contract and repeat the checks on mobile. Describe your booking journey to Niwa to connect customer assistance, website reservations and measurement around the appointment your business actually saves.