Analytics and tracking
Send Medos widget events to GA4, Google Tag Manager and Mixpanel from the callbacks, which widget fires what, and how to keep personal data out.
The widgets don't ship their own analytics — you own the data. Send events from their callbacks to whichever tool you use.
| Widget | Conversion event | Other events |
|---|---|---|
| Booking | onSuccess — a completed booking | onError, onClose |
| Enquiry form | onSuccess — a filed enquiry | onError, onClose |
| Patient portal | None — it has no completion event | onError, onClose |
| Package purchase | None — onComplete is a button handler, not a sale | — |
The recipes below use the booking widget.
Read the payload shape first
Every recipe below reports the conversion from
onSuccess. The token number lives inside
result.queueToken — a top-level result.tokenNumber is always undefined,
so a recipe copied from an older version of this page silently records
null for every queue booking.
GA4 (gtag)
MedosBooking.init({
apiKey: "mk_...",
onSuccess: (result) => {
gtag("event", "generate_lead", {
event_category: "medos_booking",
appointment_id: result.appointmentId ?? null,
token_number: result.queueToken?.tokenNumber ?? null,
payment_method: result.paymentMethod?.kind ?? null,
});
},
onError: (err) => {
gtag("event", "medos_booking_error", {
error_message: err.message,
});
},
});Google Tag Manager
Push events onto dataLayer and let GTM handle routing:
MedosBooking.init({
apiKey: "mk_...",
onSuccess: (result) => {
window.dataLayer?.push({
event: "medos_booking_success",
appointmentId: result.appointmentId ?? null,
tokenNumber: result.queueToken?.tokenNumber ?? null,
paymentMethod: result.paymentMethod?.kind ?? null,
});
},
});Mixpanel
MedosBooking.init({
apiKey: "mk_...",
onSuccess: (result) => {
mixpanel.track("Booking Completed", {
appointmentId: result.appointmentId ?? null,
tokenNumber: result.queueToken?.tokenNumber ?? null,
paymentMethod: result.paymentMethod?.kind ?? null,
});
},
onError: (err) => {
mixpanel.track("Booking Error", { message: err.message });
},
});Tracking the full funnel
Step-by-step funnel events — patient entered a contact, verified a code, picked
a slot — aren't exposed. What you can collect from the widget is the two ends of
the funnel: onSuccess for a completed booking, and onClose for a modal that
was dismissed. Everything in between needs platform-side instrumentation, so
talk to the platform team if you need it.
The enquiry form
The enquiry form has its own onSuccess,
which fires with the submitted form values rather than a server id. It's a
useful second conversion event — just don't forward the payload itself, which
is all personal data:
MedosEnquiry.init({
apiKey: "mk_...",
mode: "inline",
containerId: "medos-enquiry",
onSuccess: () => window.dataLayer?.push({ event: "medos_enquiry_submitted" }),
});Don't send PII
Never send patient names, phone numbers, or emails to third-party
analytics without explicit consent — GA4 and Mixpanel both prohibit PII
in event properties. Stick to booking IDs, token numbers, and the payment
method. result.queueToken.patientName is PII: don't pass the token object
through wholesale.