Google Tag Manager
Fire SalesCal booking lifecycle and salespad engagement events into your own GTM container.
The Google Tag Manager integration loads the standard GTM snippet on your booking pages and salespads, and pushes structured salescal.* events into the dataLayer at key moments. You then wire those events to destinations (GA4, Google Ads, LinkedIn Insights, etc.) inside GTM — SalesCal doesn't talk to those tools directly.
Setup
- Get your container ID from Google Tag Manager — it looks like
GTM-XXXXXXX(uppercase letters and digits, no lowercase). - In SalesCal, go to Integrations > Google Tag Manager.
- Paste your container ID and click Save.
- The snippet starts loading on the next page view of any booking page or published salespad.
You can disconnect at any time from the same screen — the snippet stops loading immediately on subsequent page views.
One container per workspace. All your booking pages and salespads share the same GTM container. If you need separate environments (test vs production), use GTM's built-in environments feature inside your container.
Where the snippet loads
- Booking pages (the embedded widget and the standalone slide-form layout)
- Published salespads (every page on your
*.salescal.sitesubdomain)
The snippet renders before any custom head scripts you've added per salespad, so window.dataLayer is initialized before anything else runs.
It does not load on:
- The SalesCal dashboard itself (
app.salescal.ai) - The booking-widget preview inside the event builder (preview mode should never fire real events into your own browser session)
Booking events
These fire from both the inline booking widget and the slide-form layout. Every event includes the same base payload — fields that don't apply are null.
salescal.potential
Fires twice in the typical flow:
- When the lead enters and submits their email
- Again when the lead enters and submits their phone number (if the form asks for it)
Use this for top-of-funnel "engaged" events in GA4 / ad platforms.
salescal.qualified
Fires when the lead completes the form and passes all qualification rules. The next screen will be the calendar / time picker.
salescal.disqualified
Fires when the lead completes the form and fails one or more qualification rules. The next screen will be the disqualification page. Includes the matched rule's reason in disqualificationReason.
salescal.booked
Fires when the lead picks a time slot and the meeting is created. Includes meetingId and scheduledAt.
Booking event payload
{
"event": "salescal.qualified",
"leadId": "uuid",
"eventId": "uuid",
"eventSlug": "discovery-call",
"eventName": "Discovery Call",
"teamId": "uuid",
"email": "lead@example.com",
"firstName": "Jane",
"lastName": "Doe",
"phone": "+15551234567"
}Extras per event type:
| Event | Additional fields |
|---|---|
salescal.disqualified | disqualificationReason: string | null |
salescal.booked | meetingId: string, scheduledAt: string (ISO 8601) |
Salespad events
Fire from any published salespad on your *.salescal.site subdomain.
salescal.salespad_view
Fires once when the salespad page mounts.
{
"event": "salescal.salespad_view",
"salespadId": "uuid",
"slug": "spring-launch",
"teamSlug": "acme"
}salescal.salespad_click
Fires when a visitor clicks a tracked CTA on a salespad — Button blocks, Button Modal blocks, Image blocks with links, and Hero CTA buttons.
{
"event": "salescal.salespad_click",
"blockId": "uuid",
"blockType": "button",
"label": "Book a call",
"url": "https://...",
"clickAction": "link"
}PII and hashing
The booking events push plain-text email, firstName, lastName, and phone into the dataLayer. If you need hashed values (for example, GA4 Enhanced Conversions or Google Ads Enhanced Conversions for Leads), hash them inside GTM:
- In GTM, create a Custom JavaScript Variable
- Read the raw email / phone from the dataLayer
- Hash with SHA-256 (Google's Enhanced Conversions support libraries do this)
- Pass the hashed variable to your tag instead of the raw field
Doing it inside GTM keeps the hashing logic in your hands and avoids us prescribing an algorithm you can't change.
Tag Assistant and debugging
Use Google's Tag Assistant to preview events in real time:
- Click Preview in the top right of your GTM container
- Enter the URL of one of your booking pages or salespads
- Submit the booking form / click a CTA
- Watch the events appear in Tag Assistant with their full payloads
If events don't appear:
- Confirm the container ID is saved in SalesCal (Integrations > Google Tag Manager)
- Confirm GTM's Publish workflow has actually shipped a live container (a brand-new container with no version published won't fire any tags)
- Check the page source — you should see
<script>containinggoogletagmanager.com/gtm.js?id=GTM-...
What's not included (yet)
These events are on the roadmap but don't fire in v1:
- Meeting reschedule, cancel, or outcome change (won, lost, no-show) — those happen on the manage-meeting and dashboard flows, which don't currently load GTM
- Salespad scroll-depth or video-engagement events
- Server-side events (everything is browser-side today)
- Multiple containers per workspace
- Per-event opt-out
If any of these matter, let support know — priority is driven by demand.