Integrating Calendly with Google Analytics

Wednesday, Sep 23, 2020| Tags: Calendly, Zapier, Google Analytics

Calendly has a native Google Analytics integration and it is perfectly adequate for some uses. In my case, I’m using Calendly as my main source of lead generation on my website and as an analyst the default tracking is not sufficient because I want to look at my Calendly data as part of an integrated marketing plan whereas the native Calendly-GA integration is best suited to looking at Calendly in isolation.

Problems with Calendly Native

The first problem is that Calendly’s native GA integration tracks on without doing anything to link to your site. My 15 minute meeting page is, for example.

If I were to link to the Calendly signup page from my site, a new session would start in Google Analytics with a new user. I would then lose the connection to all of the actions that led up to that session and I would add a new session and a new user to my site metrics.

In addition, because Calendly only fires GA events for lands on scheduling page, chooses an event type, selects a date, selects a time, and schedules a meeting with you without any pageviews, you will end up with a Landing Page of (not set) which can be confusing for some.

Calendly Default Tracking

Calendly lets you pass UTM parameters to their page or their embedded widgets. This gives you some tracking options but it doesn’t fix the problem of integrating Calendly tracking with tracking other marketing activities because it still starts a new session with a new user in GA just with a source/medium of your campaign parameters.

Tracking Calendly in Isolation

If you are not going to the effort to integrate Calendly tracking with your other marketing analytics as I will describe later, then I recommend that you use Calendly’s native GA integration and set up a new GA property to track your Calendly pages in isolation.

If you link to your Calendly page from your website, then you should tag those links with UTM parameters like campaign is page_name, a source of, and a medium of referral. This would let you see that the meeting came from your site (or sites) and which page referred the conversion.

It’s useful, particularly where you are letting people book from various other sources like email footers, in the text of a drip campaign, at the end of a webinar, or in a YouTube video given that you are also tagging all of these campaign links.

However, you can’t see that someone arrived by Google Search, and clicked around a few pages before finally booking a meeting.

Tracking Calendly in Isolation with Initial Source

If you want to track how someone arrived at your site before clicking to your Calendly booking page, you could write a script to save campaign parameters to a cookie recording how they arrived at the landing page and pass those to Calendly via UTM parameters using campaign of original_campaign, source of original_source, and medium of original_medium.

Calendly Tracking Using Initial Source

You would still lose all of the intervening page views and events, but it would let you analyze how they got to your site before booking a meeting rather than how they got to the Calendly page.

The bigger problem is that this works great when every link to your site is tagged, but it takes more thought when you want to add untagged sources and mediums.

Google Analytics uses a set of rules for determining the channel groupings described in these docs. You are going to need to pass the data that goes in to determining these channel groupings using tracker.get with the tracker fields from the tracking sources section and write them to a cookie.

The problem is that the tracker object only has sources and mediums deliberately set through UTM parameters. The source and medium values in the channel grouping rules are created from various rules at processing time setting, for example, as social.

Because the Calendly integration only lets you set UTM parameters you’ll need to manually recreate these rules in JavaScript and write them to UTM parameters. This gets even more complicated when you factor in things like the Google Ads integration with GA which passes ad data in the background.

I’m not sure that capturing the initial source is better than the default behaviour. And it’s a lot more work than the integrated Calendly tracking method that I’m about to describe.

Integrated Calendly Tracking

If you want to see the source and medium, all of the page views and events on your site before setting up a meeting, you need to pass the GA client ID to Calendly. And since Calendly isn’t configured to catch the client ID, it would seem that we’re out of luck.

There is a way we can make this work, though.

We can’t natively pass the GA client ID to Calendly, but we can pass data to Calendly using UTM parameters and capture that data in their Invitee Created Event API response which we can use to trigger measurement protocol hits to GA and map the UTM parameter where we store the client ID to the measurement protocol GA client ID.

The disadvantage of this approach is that you don’t get the more fine-grained event data of the native Calendly integration, like the select a date and select a time events, but the most important event is the schedules a meeting with you event and we are getting that event.

Since I’m not driving PPC traffic directly to my Calendly booking page, I can use the utm_term parameter without breaking my standalone Calendly GA property. Even if you do drive traffi directly to Calendly using PPC, you can analyze UTM term normally and just filter out the client IDs which are pretty obviously not PPC terms that you would bid on.

To make things really simple, you can use the Zapier integration with Calendly to send those measurement protocol hits so you don’t need to write authorization code and measurement protocol hits.

But you do need to customize your GA snippets in Google Tag Manager and write a little bit of JavaScript code.

First, create a Custom Javascript variable in GTM and use a customTask to capture the clientID using the below code.

You’re going to need the name of that Custom Javascript variable, so copy and save it somewhere handy. I named mine GA - ClientID.

Next, edit the embed code on your site and give it an ID. I used id=”calendar” on my site. If you are linking to your booking pages on the Calendly site, give the link the ID. While we are here, we’re also going to drop the <script> link part of the embed code (but save the src) we’re going to need it later. It’s best to copy the embed code from Calendly and make the necessary alterations here rather than copying this code.

Now you’re going to target that ID and append &utm_term=<client_id> to the Calendly link. Create a Custom HTML tag with the following code.

You’re going to need to edit the code in a few places.

On line 3, change “calendar” to whatever ID you used for your embed code.

On line 4, copy the URL from your embed widget and replace the main portion of the URL with your URL. Don’t worry if you have more parameters than the example.

Still on line 4, add &utm_term= to the end of the URL. If you don’t have any other URL parameters, replace the ampersand (&) with a question mark (?).

Still on line 4, replace the text between the double curly braces with the name of the Custom Javascript variable that you saved from earlier. That is GA - ClientID in my example.

We schedule this to run when the page is loaded to make sure all of the HTML is in place using the GTM Page View - Window Loaded trigger.

Add UTM to Calendly in Google Tag Manager

The Calendly link doesn’t do anything on its own other than to pass configuration settings when embedded like this.

The Calendly script immediately below the embed code is what sets things in to motion. However, we need to make sure that the script waits for our client ID to be ready.

The simple way to do this is to open the script URL, copy all of the code to a Custom HTML tag, and sequence the tag to run after everything else is done.

At the time of writing, the script is at

Copy and paste that to the HTML section of your Custom HTML tag and don’t forget to enclose that in script tags.

You could at this point trim this script down, you don’t need the code to wait until the page has loaded and you don’t need the code for any embed types that you’re not using, but we should be passing the Client ID now with no extra effort.

Save it and ignore the warning that the script has no trigger.

Finally, go back to the Custom HTML tag that adds the UTM parameter to Calendly, edit it and under the Advanced Settings > Tag Sequencing set Fire a tag after Add UTM to Calendly fires and select the Calendly script Custom HTML tag that you just created helpfully named Calendly Script in the example below.

Trigger Calendly script to fire after the Add UTM tag

That should be all of the coding done. You’re going to need a meeting booked with the client ID in utm_term to do the next step, so go test out the booking flow in GTM Preview mode and make sure that the client ID is being passed in UTM Term.

Zapping Your Way to Completion

Let’s move on to Zapier.

Create a new Zap triggered by Calendly. Choose the Invitee Created trigger, authenticate and check for the Tracking UTM Term field exists with the client ID.

Add a Filter step to remove any submissions that don’t have a client ID by checking that the Tracking UTM Term field from the Calendly trigger does not equal n/a.

Zapier filter removing client ID not set entries

Next, set up a Google Analytics Create a Measurement action. Authenticate and then select your Account, Property, and Type.

Event is probably the best type, but some might want to choose Page View. You could also make an argument to make this an ecommmerce transaction, but you’re going to have to custom code that since it’s not an option in Zapier.

Next, set your Event Category, Event Action, Event Label, Event Value and Custom Client Id.

I chose to hard code the category, action, and value and use a label from a custom field that I added to my Calendly forms and the utm term field from the Calendly Invitee created trigger. I probably should have created a lookup table in Zapier to map the Event Value to different event labels since some answers that I configured, like Sell your awesome product, are worth less than others.

GA measurement protocol event settings and client ID in Zapier

And that’s it.

But wait, there’s more

Since you’re in Zapier already, you might as well chain an add contact action to your CRM, configure your CRM to save client IDs, and pass the client ID and contact details to the CRM.

I won’t go exactly in to how to do this in Zapier because it depends on the CRM, but if you got this far, it isn’t too difficult.

You can also add this person to your address book if that’s worthwhile.

You can also add an activity with your meeting time to your CRM as well.

You can also create a Lookup Table in Zapier and map the Purpose of Meeting fields to different values and plug those in to the Event Value fields in the measurement protocol hits sent by Zapier.

And since you’ve saved the client ID to your CRM, you can create another Zap triggered by completing the CRM activity to send that interaction back to GA as either a page view or an event which will help you understand the interplay between web traffic and phone calls.

Bonus Points: App & Web

Google doesn’t officially support measurement protocol hits to App & Web, but one intrepid analyst figured out how to send them anyway.

In order to track App & Web in Zapier, you’re going to want to use the Zapier code module. We’re not doing anything too difficult here, but you should be familiar with code.

The App & Web docs tell you how to set up App & Web alongside Universal analytics and use the same client IDs for both properties. The GTM documentation doesn’t specify whether the client IDs are the same when set up via GTM, but I can confirm that this is the case so we don’t need to add any extra code to capture two client IDs when running Universal and App & Web side-by-side through GTM as I am doing.

I’m going to show the Python code that I used for App & Web but you can probably use this even if you only code JS since there’s not a lot there.

First, you’ll need to create a map your client ID field to a variable that your script can access. I named my variable cid and it will be available in code through the input_data[‘cid’] variable.

Next, add this code, set your TID, and test that it is running properly.

I chose to use the generate_lead native event from App & Web. If you choose something else, you’ll need to modify this code including the ‘ep.currency’ : ‘USD’, and ‘epn.value’ : ‘50’.

You should chain this code to the main Calendly Zap, presuming that you’re running App & Web in parallel with Universal Analytics, since you’re charged by the number of Zaps that you trigger and not by the number of steps within them.

Zapier’s code module expects you to return an output that you can map to other apps. Since the main work of sending the measurement protocol hit to GA is already done, you can map errors to this output and then use Zapier to send those errors to a Slack channel or other notification channel for extra bonus points. The GA measurement protocol doesn’t return errors, but you can write some validation in the script that sends the measurement protocol hit, like validating that the _tid _is in the proper format for App & Web.

All done.

For real.

This time.

Get Updates

You're data will be protected in accordance with our privacy policy.

The Refresher ~ Analytics for Marketers

Marketer-friendly summary of the most important changes to browsers, privacy laws, and analytics delivered quarterly to your inbox.

Learn More

Let's talk about your data

I want to help you get more from your data now while setting up culture and processes that will help you scale your data analytics team in the future.

Schedule a Call