GA4 has no recommended event for a booked meeting. Fire a custom booked_call event the moment your scheduler confirms the slot, mark it as a key event under Admin > Data display > Events, and put a dollar value on that one event only. A standard property allows 30 key events; this schema uses three.
At a glance
- The event:
booked_call— custom, because Google’s recommended-event reference has no scheduling event. The closest documented ones aregenerate_leadandworking_lead. - Where to mark it: Admin > Data display > Events > Mark as key event toggle.
- Counting method: Once per event (Recommended), not Once per session (Legacy).
- The value: average contract value × show rate × close rate. Worked below at $2,692.80.
- What breaks it: a scheduler iframe on another domain, duplicate fires on the confirmation page,
analytics_storagedenied, and attribution that moves for up to 12 days.
Which GA4 event should a booked call fire?
A custom one. Google’s gtag.js event reference documents a lead-generation set — generate_lead, qualify_lead, working_lead, close_convert_lead, disqualify_lead — and none of them means “a specific human agreed to a specific time.” generate_lead is the form fill; working_lead is contact with a rep. The calendar slot sits between them and has no name, so you name it.
Use booked_call, and do not overload generate_lead to mean both. Web data streams have no limit on distinctly named events, so there is no reason to economize. Event names and parameter names are capped at 40 characters and parameter values at 100, per Google’s event collection limits — which is why you send a short source code, not a full landing-page URL.
How it works
From confirmed slot to a GA4 key event you can trust
Fire booked_call on confirm
The moment the scheduler confirms a slot, send a custom booked_call event with booking_id and meeting_type. Google’s recommended-event reference has no scheduling event, so you name this one.
Mark it a key event
In Admin under Data display, open Events and switch on Mark as key event. Set the counting method to Once per event, not Once per session.
Value it exactly once
Set value to average contract value times show rate times close rate. Only one event in the chain carries a value, or GA4 sums the same booking twice.
Reconcile against the CRM
Send held and no-show back from the server as working_lead, using the client_id stored at booking time. Compare GA4, the scheduler export and the CRM monthly.
MAKE MORE SALES.
Pay-Per-Result pricing — We scale sales HARD aligned to your interests, better than anyone else.
The booked-call event schema, with the exact parameters
One event per state change, and never rewrite a state. This is the whole implementation:
| Event | Fires when | Google’s status | Parameters to send | Mark as key event? |
|---|---|---|---|---|
generate_lead |
Form submitted, call answered, lead record created | Recommended: currency, value, lead_source |
lead_source only — no value |
No |
booked_call |
Scheduler confirms the slot | Custom — no recommended equivalent exists | value, currency, booking_id, meeting_type, days_to_meeting |
Yes |
working_lead |
Rep and buyer are actually on the call | Recommended: currency, value, lead_status |
lead_status = held or no_show, booking_id |
Yes |
close_convert_lead |
Contract signed | Recommended: currency, value |
Actual contract value, booking_id |
Yes |
Three key events out of the 30 a standard property allows, against 50 event-scoped custom dimensions to register the parameters to, per Google’s configuration limits. The booking_id is the join key that lets you reconcile GA4 against your scheduler and your CRM, and it is the parameter almost every implementation leaves out.
Want this done for you? We book qualified sales appointments on a Pay-Per-Result basis — you only pay for calls that actually land in your calendar.
How do I mark booked_call as a key event in GA4?
In Admin, under Data display, click Events, find booked_call and switch on the Mark as key event toggle. The event must have fired at least once to appear there, so send a test booking first.
Then check the counting method, which is the setting people miss. Google documents two options: Once per event (Recommended) and Once per session (Legacy). New key events default to once per event; anything migrated from a Universal Analytics goal defaults to once per session. You change it from the Key events tab of that same Events list — the row’s More menu, then Change counting method — and it needs Marketer permissions or above (Google Analytics Help). A buyer who books two calls in one session booked two calls. Once-per-session quietly throws the second one away.
How do I get the booking out of Calendly and into GA4?
Scheduler-specific, so: this is Calendly, using two features Calendly itself documents. The right mechanism depends on whether the booking completes on your domain or theirs.
Option A — the parent-page listener (inline or popup embed). Calendly’s embed posts four events to the parent window: calendly.profile_page_viewed, calendly.event_type_viewed, calendly.date_and_time_selected and calendly.event_scheduled (Calendly Help). Add a message listener on your own page; on calendly.event_scheduled, push to the data layer and fire the GA4 event from Tag Manager. Everything stays in your own session, which is the point.
Option B — Calendly’s native GA4 integration. Automations > Integrations & apps > Google Analytics, paste your G-XXXXXXXXXX Measurement ID, save. Calendly then sends seven of its own invitee events, including invitee_meeting_scheduled. Read the limitations before you choose it: one Measurement ID per Calendly organization, no per-user or per-team tracking codes, and “Calendly doesn’t support direct integration with Google Tag Manager at this time” (Calendly Help). It also requires a paid tier — Professional, Standard, Standard Plus, Teams, Teams Plus or Enterprise.
A redirect-style booking link also needs cross-domain measurement: Admin > Data collection and modification > Data streams > Web > select the stream > Configure tag settings > Configure your domains. Google’s cross-domain documentation is explicit that the _gl linker parameter passes “when the user navigates between domains through a link or a form”. An iframe’s src is neither, which is why cross-domain settings never fix an embedded scheduler — that is our reading of the mechanism, not a sentence Google writes down.
If we can’t make you money, we don’t deserve yours.
Pay-Per-Result pricing — performance-based alignment.
What value should I put on a booked_call event?
Not the deal size — the expected value of the slot, which is the deal size discounted by the two things that have not happened yet:
value = average closed contract × show rate × close rate on held calls
Worked with US consulting numbers: an $18,000 average contract, a 68% show rate and a 22% close rate on held calls gives $18,000 × 0.68 × 0.22 = $2,692.80. That is what you send as value, with currency: "USD". Substitute your own three numbers; if you do not have a measured show rate, you are not ready to value the event, and our write-up on why booked calls do not show up for high-ticket offers is the prerequisite.
The single-value rule: exactly one event in the chain carries value. GA4 sums key event values, so if you also value generate_lead, one booking reports twice and Smart Bidding optimizes toward an inflated number. Put the value on the event you want bids to chase — usually booked_call — and send the rest with no value at all. The event then feeds a real unit cost: our US cost per booked call benchmarks for 2026 are the denominator it was always missing, and the US cost per lead benchmarks are what generate_lead feeds.
Why is my GA4 booked-call count different from my scheduler’s?
Four causes, in the order we find them. Test before you fix: three of the four undercount and look identical in the reports.
| Symptom | Cause | Test that distinguishes it | Fix |
|---|---|---|---|
GA4 shows far fewer bookings; calendly.com appears as a session source |
The booking completes inside an iframe on the scheduler’s domain. Your tag never runs in there | Reports > Traffic acquisition, filter session source for the scheduler’s domain | Parent-page calendly.event_scheduled listener (Option A above) |
| GA4 count roughly double the scheduler’s export | The event fires on a confirmation page_view and from a webhook or server call |
Count both sources over the same 30-day window against the scheduler export | Fire from exactly one place. GA4 does not deduplicate custom events for you |
| Count drops the week a cookie banner ships | analytics_storage denied — events “are not associated with a persistent user identifier” |
Compare the 14 days either side of the banner going live | Advanced consent mode, so tags load in all cases and behavioral modeling can fill the gap |
| Yesterday’s number keeps moving for a week and a half | Attribution and modeling settle late | Re-pull the same date range 12 days later and diff it | Judge campaigns on a closed window, not on today. Google states attributed conversion data can be updated for up to 12 days |
The consent row is the one that turns into an argument with finance. Google’s consent-mode documentation is where the “not associated with a persistent user identifier” wording comes from, and its documentation on modeled key events is blunt about the limit: modeled key events “are only included when there is high confidence of quality,” and “if there isn’t enough traffic to inform the model, then modeled key events aren’t reported.” A low-volume US site with a strict banner sees a smaller number and no amount of tagging recovers it. Say that out loud before someone concludes the ad spend stopped working.
How do I record the calls that actually happened?
From the server, because attendance is known to your CRM hours after the browser session ended. Send working_lead with lead_status: "held" or "no_show" through the Measurement Protocol: POST https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=YOUR_SECRET, body carrying client_id and an events array of name and params (Measurement Protocol).
Two documented constraints decide whether this is worth building. You must store the client_id at booking time and pass it to your CRM, or the server event cannot be joined to the session that produced it. And Google states that “rules for generating or renaming events aren’t triggered by events sent with the Measurement Protocol,” so tidying done in the GA4 interface will not apply — the server payload has to be right on the way out.
What this costs to run, and when to stop doing it yourself
Honestly: the tagging is an afternoon and the maintenance is the job. In our own implementations the GTM work lands in about half a day for someone who has built a data layer before, then roughly an hour a month reconciling three numbers — GA4 key events, the scheduler’s export and the CRM. That hour is what catches the duplicate-fire failure above before it reaches a bidding strategy. It breaks whenever the scheduler changes its embed, which is not on your release schedule.
| Booked calls per month | What is actually worth building |
|---|---|
| Under ~20 | The scheduler’s own export is your source of truth. One booked_call key event for channel attribution, no value, no server events |
| ~20–100 | The full four-event schema with GTM, values on booked_call, monthly reconciliation |
| 100+ | Server-side: CRM is the source of truth, Measurement Protocol feeds GA4, client_id stored on every record |
Below about 20 bookings a month the reconciliation costs more hours than the reporting saves, and the honest advice is to skip it. Past that, the constraint stops being analytics and becomes operations: we publish how we define the sales lift we report on our methodology page, and the call volume this schema exists to count is what AI appointment setting produces.
Frequently asked questions
Is a booked call a conversion or a key event in GA4?
In Analytics it is a key event. Google now reserves “conversion” for Google Ads, where it means an action used to measure campaign performance and optimize bidding; a key event is an Analytics event measuring “an action that’s particularly important to the success of your business.” The two were split because they had been measured differently and the numbers disagreed (Analytics Help: conversions vs. key events). Practically: mark it as a key event in GA4, then import it into Google Ads as a conversion.
How do I track Calendly bookings in GA4 without Google Tag Manager?
Use Calendly’s native integration — Automations > Integrations & apps > Google Analytics, paste your Measurement ID. Note that it is one Measurement ID per organization and that Calendly states it “doesn’t support direct integration with Google Tag Manager at this time” (Calendly Help). You get Calendly’s event names, not yours, which is fine for reporting and awkward for Ads.
How many key events can I have in a GA4 property?
Thirty on a standard property, along with 50 event-scoped custom dimensions, 25 user-scoped ones and 100 audiences (Analytics Help: configuration limits). The booking schema on this page uses three of the thirty.
Why does GA4 show fewer booked calls than my scheduler?
Usually the iframe, sometimes consent. If the scheduler’s domain shows up as a session source in Traffic acquisition, the booking is completing on their origin and your tag is not there. If the gap opened the week a cookie banner shipped, analytics_storage is being denied and the events are no longer tied to a persistent identifier. Both undercount, and they look the same in the report.
Can I send a booked call to GA4 from my CRM instead of the browser?
Yes, via the Measurement Protocol, but only if you stored the client_id at booking time. Google is explicit that the protocol is “intended to supplement, not replace, automatic data collection methods like gtag, Tag Manager, and Google Analytics for Firebase,” and that only partial reporting may be available without them (Measurement Protocol overview).
Pay-Per-Result appointments
See if we’re a fit
We book qualified sales appointments for you and you pay on results, not retainers. Our booking page asks a few quick questions so you find out in two minutes whether that model suits your business.
- 50,769+ appointments booked without cold calling.
- Pay-Per-Result pricing — you pay for booked, qualified calls.
- Pick your own time on our live calendar, no phone tag.
