---
title: "Google Tag Manager"
description: "Fire SalesCal booking lifecycle and salespad engagement events into your own GTM container."
url: https://help.salescal.ai/en/articles/22-google-tag-manager
collection: "Integrations"
updated: 2026-10-19
language: en
---

# 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

1.  Get your **container ID** from Google Tag Manager — it looks like `GTM-XXXXXXX` (uppercase letters and digits, no lowercase).
    
2.  In SalesCal, go to **Integrations** > **Google Tag Manager**.
    
3.  Paste your container ID and click **Save**.
    
4.  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.site` subdomain)
    

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

```json
{
  "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:**

<table data-id="66e54e50-696c-4da2-9914-f8b275852067" style="min-width: 50px;"><colgroup><col style="min-width: 25px;"><col style="min-width: 25px;"></colgroup><tbody><tr><td colspan="1" rowspan="1"><p data-id="6f2835f3-5629-4d3f-ac9b-205dc20c63ff">Event</p></td><td colspan="1" rowspan="1"><p data-id="5c5a58b6-77ca-420b-ae6d-178c4c2f2b34">Additional fields</p></td></tr><tr><td colspan="1" rowspan="1"><p data-id="6451690e-ac1a-4697-8909-97464a8cf4b2"><code>salescal.disqualified</code></p></td><td colspan="1" rowspan="1"><p data-id="995652e6-a266-47c7-8b54-7e40d0e0fefc"><code>disqualificationReason: string | null</code></p></td></tr><tr><td colspan="1" rowspan="1"><p data-id="65d17e6e-40e3-44a5-aa3e-dea348224824"><code>salescal.booked</code></p></td><td colspan="1" rowspan="1"><p data-id="febbbcd0-0e6f-4710-90c2-28bc3e1c70a2"><code>meetingId: string</code>, <code>scheduledAt: string</code> (ISO 8601)</p></td></tr></tbody></table>

## Salespad events

Fire from any published salespad on your `*.salescal.site` subdomain.

### `salescal.salespad_view`

Fires **once** when the salespad page mounts.

```json
{
  "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.

```json
{
  "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:

1.  In GTM, create a **Custom JavaScript Variable**
    
2.  Read the raw email / phone from the dataLayer
    
3.  Hash with SHA-256 (Google's Enhanced Conversions support libraries do this)
    
4.  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](https://tagassistant.google.com/) to preview events in real time:

1.  Click **Preview** in the top right of your GTM container
    
2.  Enter the URL of one of your booking pages or salespads
    
3.  Submit the booking form / click a CTA
    
4.  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>` containing `googletagmanager.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.
