Default page views are not enough. Product and marketing need events for Contact submits, Rent a developer clicks, and WhatsApp taps. This tutorial sets up a clean `dataLayer` contract and matching GTM triggers.
What you will build
- A typed `pushDataLayerEvent` helper
- Events for `cta_click`, `contact_submit`, and `whatsapp_click`
- GTM Custom Event triggers + GA4 Event tags
- A QA checklist in Preview mode
Prerequisites
- GTM installed on the site (see our install tutorial)
- GA4 property connected in GTM
- Ability to edit React/Next components for key CTAs
Step-by-step
- Define event names and parameters in a short analytics README (source of truth).
- Add `lib/analytics/data-layer.ts` with a safe `window.dataLayer.push` wrapper.
- Fire `cta_click` when primary buttons are clicked (`location`, `label`).
- Fire `contact_submit` after a successful contact API response (`intent`: meeting | project | hire).
- In GTM, create Custom Event triggers for each event name.
- Attach GA4 Event tags that map parameters to GA4 event params.
- Publish a GTM version and validate in DebugView.
dataLayer helper
type DataLayerEvent = {
event: string;
[key: string]: string | number | boolean | undefined;
};
export function pushDataLayerEvent(payload: DataLayerEvent) {
if (typeof window === "undefined") return;
window.dataLayer = window.dataLayer || [];
window.dataLayer.push(payload);
}CTA example
<button
type="button"
onClick={() =>
pushDataLayerEvent({
event: "cta_click",
cta_location: "home_hire",
cta_label: "Rent a developer",
})
}
>
Rent a developer
</button>Contact success example
pushDataLayerEvent({
event: "contact_submit",
intent: "hire",
hire_plan: "monthly",
});GTM configuration
- Trigger: Custom Event → Event name equals `contact_submit`.
- Tag: GA4 Event → Event name `contact_submit`.
- Event parameters: `intent`, `hire_plan` from Data Layer Variables.
- Repeat for `cta_click` and `whatsapp_click`.
Verify
- Preview mode shows the event on submit
- GA4 DebugView receives the event within a minute
- No PII (emails, phone numbers) in event params
Common mistakes
- Pushing events before GTM loads (queue with dataLayer anyway; GTM reads history)
- Reusing vague names like `click` without parameters
- Tracking every link and drowning the property in noise
Next steps
Mark `contact_submit` as a key event (conversion) in GA4, then build an exploration for intent mix (meeting vs project vs rent).


