Task 2

GA4 Event Spec via GTM

Rendered implementation flow for firing booking_completed after a patient reaches the booking thank-you page.

Assignment Brief

On the same WordPress site as Task 1, a patient completes a multi-step booking form ending on a thank-you page. Fire a GA4 custom event called booking_completed with booking_id, state, product_type, and value.

Rendered Event Flow

The diagram below shows exactly where the data layer push, GTM trigger, GA4 tag, validation, and de-dupe guard sit in the booking journey.

sequenceDiagram participant Patient participant WP as WordPress Thank-You Page participant DL as dataLayer participant GTM participant GA4 Patient->>WP: Completes final booking step WP->>WP: Persist booking and render final values WP->>DL: Push booking_completed with booking_id, state, product_type, value DL->>GTM: Custom Event trigger receives booking_completed GTM->>GTM: Validate thank-you path, required fields, and booking_id de-dupe key alt Valid event GTM->>GA4: Send booking_completed event parameters GA4-->>GTM: Confirm in DebugView / Realtime else Invalid or duplicate GTM-->>WP: Block GA4 tag and log non-PII staging warning end

Data Layer Push on Thank-You Page

Push from the server-rendered thank-you template only after the booking has been persisted and the confirmation page has the final booking values.

<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  event: 'booking_completed',
  booking_id: 'BK-20260426-8F31',
  state: 'FL',
  product_type: 'initial_certification',
  value: 99.00,
  currency: 'USD'
});
</script>
  • Do not push patient name, email, diagnosis, condition, appointment notes, or medical history.
  • Render values from trusted server-side booking data, not client-entered form fields.
  • Recommended page scope: /booking/thank-you/ or the production equivalent.

GTM Trigger

  • Trigger type: Custom Event.
  • Event name: booking_completed.
  • Conditions: Page Path matches RegEx ^/booking/thank-you/?$.
  • Require booking_id, state, product_type, and value.
  • Fire once per booking, not once per page refresh.

Data Layer Variables

  • DLV - booking_id maps to booking_id, version 2.
  • DLV - state maps to state, version 2.
  • DLV - product_type maps to product_type, version 2.
  • DLV - value maps to value, version 2 and should be treated as a number.
  • DLV - currency maps to currency; use USD.

GA4 Event Tag

  • Tag type: GA4 Event.
  • Measurement ID: use the existing GA4 configuration variable or GTM constant variable.
  • Event name: booking_completed.
  • Event parameters: map each data layer variable to the same parameter name.
  • Mark as a GA4 key event only after QA confirms no duplicate sends.

De-Dupe Guard

const key = `booking_completed_sent_${booking_id}`;
if (!sessionStorage.getItem(key)) {
  sessionStorage.setItem(key, '1');
  // allow GA4 event tag to fire
}
  • Use booking_id as the de-dupe key.
  • Prefer server-side single rendering where possible; use browser storage as the last-mile guard.

Validation

  • Use GTM Preview mode and complete a test booking through the thank-you page.
  • Confirm the data layer event appears once with all required parameters.
  • Confirm the GA4 Event tag fires only on the custom event, not on page view.
  • Open GA4 DebugView and verify booking_completed with expected values.
  • Refresh the thank-you page and verify the de-dupe guard prevents a second event.

Privacy and Failure Rules

  • No PHI in GTM or GA4: no condition, symptom, diagnosis, notes, name, email, phone, or address.
  • If a required parameter is missing, block the tag and log a non-PII warning in staging.
  • If value cannot be parsed as a number, block revenue reporting until corrected.
  • Use separate product_type values for initial_certification and renewal.

Open Question / Assumption

Assumption: booking confirmation values are available server-side before the thank-you page renders, and the dev team can safely serialize only non-PHI fields into the page.

Open question: should renewals and initial certifications share one GA4 key event with product_type, or should GA4 also receive separate derived events for lifecycle audiences?