Chris More
Chris More
March 14, 2022

Streamline Funnel Analytics with Dynamic UTM Parameters


The Reporting Challenge

UTM Parameters, or "Urchin tracking module", are the standard way marketing and growth professionals measure the impact of campaigns. Even though UTM tracking tags are part of the Google Analytics ecosystem (thanks for a 2005 acquisition), many digital marketing tools and analytics platforms can also consume the UTM data.

While UTMs are ubiquitous in marketing, the best practice requires constant effort to ensure external links are tagged. The reality is that only a few links contain UTM tags. Links that do have UTMs are often only digital marketing campaigns, generated through manual tagging with the help of a campaign tracking URL builder. This creates a challenge when you want to create standard reports to compare the performance across all marketing channels if your marketing technology stack extends beyond the Google ecosystem.

At Stateful, we are using Segment as our customer data platform (CDP), and have Mixpanel, Google Analytics, and other solutions as destinations. Below is a screenshot of a Mixpanel report I created to look at the incoming sources coming to The issue is that the source analysis in Mixpanel assumes utm_source is set.

Mixpanel Source Report Before Dynamic UTMs with-shadow

What was frustrating about the report above was that I knew I was getting traffic from other sources, but those sources were not using UTM and thus were not included in the report. I created workarounds, but it was painful. The pain was relieved when I found a solution to backfill the missing source data.

This article will provide a solution to that reporting challenge described above and allow you to create streamlined reports based on your website’s traffic source by adding automatic UTM tracking.

Solving the Missing UTM Parameter Problem

It is possible with JavaScript to dynamically add UTM tags when someone visits your website from any external source. By adding the missing UTM tags, you can easily create a report comparing one source to another and be confident you are capturing all the traffic. Google Analytics does a good job of filling in missing sources, but other analytics tools rely heavily on populated UTM tags.

Now that we know it is possible to use technology to populate UTM tags, let’s see how this works in practice.

Setting Up the Logic

As a recap, the most commonly used UTM tags are:

  • utm_source = The source parameter is usually the domain or website the referring traffic came from
  • utm_medium = The medium is the category or type of referring traffic
  • utm_campaign = The campaign name or campaign parameter is usually a code used for marketing attribution

When someone visits your website, it typically includes an HTTP referring header (as seen below) that includes the full URL of where they came from before to landing on your website. We will use that header value in the logic used to populate the missing UTM tags.

HTTP Referer Header with-shadow

Let’s use this pseudocode below to explain how the logic will function.

If (utm_source.exists == FALSE) {
    utm_source = referring-hostname
    utm_medium = “referral”
    utm_campaign = “none”

We are going to set the source to the referring hostname, the medium to simply “referral”, and the campaign to “none”. Setting the medium to “referral” will also align with Google Analytics and other analytics software that uses the same medium value for non-campaign traffic from external websites.

To illustrate how this would work, if there was a link on to that did not contain UTM tags, we could dynamically set the UTM parameters to:

From the perspective of your analytics solution, it would look like the link to had UTM parameters when it did not.

Got it? Let’s dive into the code.

Show Me the Code

Here is the JavaScript that will dynamically create UTM parameters, and then I will explain how it all works. This code will be in the <head> section of your website’s HTML above any analytics tags.

const searchParams = new URLSearchParams(;
if (!searchParams.get('utm_source') && document.referrer) {
    const referrerHostname = new URL(document.referrer).hostname;
    if (referrerHostname !== window.location.hostname) {
        const url = new URL(window.location);
        url.searchParams.set('utm_source', referrerHostname);
        url.searchParams.set('utm_medium', 'referral');
        url.searchParams.set('utm_campaign', 'none');
        window.history.replaceState({}, '', url);

Let’s break down how this code works.

const searchParams = new URLSearchParams(;

The code above simply gets the URL parameters from the visitor’s browser address.

if (!searchParams.get('utm_source') && document.referrer) {

We then check to see if utm_source is not defined and if the referring URL is available.

const referrerHostname = new URL(document.referrer).hostname;

Then we set a variable using the hostname of the referring URL as the value.

if (referrerHostname !== window.location.hostname) {

Just double-check above that the hostname isn’t the current website, or we would be adding UTM parameters as a visitor is browsing each site page, which is overkill.

const url = new URL(window.location);

This is setting a variable of your visitor’s current web browser address.

url.searchParams.set('utm_source', referrerHostname); url.searchParams.set('utm_medium', 'referral'); url.searchParams.set('utm_campaign', 'none');

Then all we do is set the UTM values to the referring hostname and the two static values we discussed previously.

window.history.replaceState({}, '', url);

Finally, we replace the web browser’s current address with the newly constructed URL with the dynamic UTM parameters, which is compatable on all moderns browsers.

Voilà! Any external link to your website will be automatically tagged with UTM parameters when none are present.

Google Organic Results with-shadow

Conclusion and Considerations

While setting UTM parameters dynamically is great, there are a few items to keep in mind as this will impact reporting going forward. If you are comparing analytics before you made this change, the utm_source and utm_medium parameters will be slightly different.

For example, in Google Analytics, traffic from gets automatically tagged as “social” as the medium. With the code above and no UTM parameters, the utm_medium value would change from “social” to “referral”. Also, traffic from Google organic will change from “google / organic” to “ / referral”.

While these changes in the source and medium will slightly impact basic reporting in Google Analytics, this can be overcome by creating segments like the following:

Google Analytics Organic Segment with-shadow

The GA segment above creates a cohort of visitors that match both the historical and new values created by the dynamic UTM parameters. It is also possible to expand the functionality of this code and include an array of search engines and social media sites that could be categorized as “organic” and “social” respectively. A future follow-up blog post will explore potential advanced features.

While we have talked a lot about Google Analytics, the changes above have an even bigger impact on other analytics tools like Segment and Mixpanel that out-of-the-box doesn’t categorize sources automatically and rely more heavily on UTM parameters.

Below is a screenshot of a Mixpanel report I created to look at the distribution of traffic sources for In Mixpanel, out-of-the-box source analysis requires utm_source to be populated. If you were using the code snippet above, you can view all of your sources regardless if they were tagged with UTM parameters.

Mixpanel Source Report After Dynamic UTMs with-shadow

Boom! We now have a single report in Mixpanel that shows all of the source traffic regardless if the external links are tagged with UTM codes.

Before You Go

To stay updated with our latest content, please subscribe to our email updates or follow us on Twitter at @runmedev! Also, check out Runme (interactive runbooks for VS Code), and Runme Cloud.

Let us know what you think. Bye for now! 👋

Also check out

Hardening an Ubuntu Server with Runme
December 5, 2023
Hardening an Ubuntu Server with Runme

System hardening is an essential practice that involve securing a system by reducing its vulnerability footprint. But what if we could automate, document and streamline these processes? Enter Runme, a powerful tool that simplifies the deployment of applications and execution of commands.

Unleashing Efficiency: The Auto-Save Feature in Runme
November 21, 2023
Unleashing Efficiency: The Auto-Save Feature in Runme

The Auto-Save feature in Runme doesn’t just safeguard your work, providing a seamless and hassle-free way to ensure that your work is continuously saved to the Runme Cloud; it’s also super handy for getting a teammate involved in troubleshooting.

Escape Confluence: Better Tooling for Internal Operator Docs
November 14, 2023
Escape Confluence: Better Tooling for Internal Operator Docs

Learn what's new in Runme v2.0 and how it's an excellent solution for internal documentation to capture and spread what's otherwise tribal knowledge around your team.

© 2023 Stateful Inc. All rights reserved.