Why You Should Never Add UTM Parameters to Internal Links

UTM parameters tell analytics where a session came from. Adding them to internal links — links between pages on your own site — overwrites the original source. A user who arrived from Google Search becomes “internal newsletter banner” the moment they click your CTA. Attribution: destroyed. Here’s exactly what breaks and what to do instead.

The mechanism

When a user lands on your site with UTM parameters in the URL, your analytics records the source for the entire session. If they then click a link with new UTMs, most analytics tools start a NEW session and overwrite the source with the internal UTMs.

Concrete example:

  1. User clicks Google ad → lands on your site → utm_source=google, utm_medium=cpc.
  2. User clicks a banner on your homepage with utm_source=homepage_banner.
  3. Analytics now shows utm_source=homepage_banner. The original Google ad attribution is gone.
  4. You spent money on Google Ads. The conversion is now credited to your homepage banner.
  5. You decide Google Ads doesn’t work. You cut spend. Conversions tank.

This isn’t theoretical. It’s the most common analytics-destroying mistake in marketing.

What internal links shouldn’t have

  • utm_source
  • utm_medium
  • utm_campaign
  • utm_term
  • utm_content

None of them. Ever. On any link from one page of your site to another page of your site.

What to use instead

You can absolutely track which internal banner / CTA drives clicks. Just don’t use UTMs.

Option 1: GA4 link click events

GA4’s enhanced measurement automatically tracks outbound link clicks. For internal link clicks, set up a custom event:

// In Google Tag Manager:
// Trigger: Click - Just Links, where Click URL contains "/your-internal-target/"
// Tag: GA4 Event with name "internal_cta_click"
// Parameters: cta_location, cta_label

Now you see internal click counts without disturbing the session source.

Option 2: Custom URL parameters that GA4 ignores

Add custom parameters that aren’t UTMs:

https://yourdomain.com/pricing?cta=homepage-banner

Track the cta parameter as a custom dimension. GA4 doesn’t treat it as a session-source change.

Option 3: Hash fragments

https://yourdomain.com/pricing#cta=homepage-banner

Hashes don’t trigger source changes. They’re invisible to your server but JS / GTM can read them.

The three exceptions (sort of)

UTMs on internal links are almost always wrong. Three edge cases where they’re tolerable:

  1. Cross-subdomain navigation when you haven’t set up cross-domain tracking. Better fix: set up cross-domain tracking properly.
  2. You’re using a third-party tool that requires UTMs to track form submissions. Better fix: use a tool that doesn’t.
  3. You’re A/B testing and you NEED the UTM to differentiate variants in your analytics. Better fix: use your A/B testing tool’s native variant tracking.

In every case, the “better fix” is the answer. Avoid UTMs internally if at all possible.

How to find existing internal UTM contamination

Audit your site:

  1. Crawl your site with Screaming Frog or similar.
  2. Filter for outbound links that contain “utm_.”
  3. Check each one — if it points to your own domain, it’s the problem.
  4. Strip the UTMs from those links.

Email is the gray area

Newsletter links to your site are EXTERNAL — UTMs there are correct. The confusion: when you forward a newsletter email between team members, the team member clicks the same UTM link, and now their visit gets attributed to the newsletter. Annoying, but the alternative (no UTMs) is worse.

Treat your newsletter as external. Tag those links normally.

What about UTMs on share buttons?

Tricky. A “share on Twitter” button on your blog post adds the URL with UTMs to a tweet. When the recipient clicks that tweet:

  • If the UTMs say utm_source=twitter: clean attribution.
  • If the UTMs say utm_source=blog_share_button: lying — the actual click came from Twitter.

Use the source where the click ACTUALLY originates. Twitter, in this case.

Common mistakes

  • UTM-tagging your homepage’s CTA buttons. Catastrophic. Strip them now.
  • Using UTMs in internal nav menus. Same problem.
  • Forgetting that “internal” includes your subdomains. If you have www.x.com and blog.x.com, links between them shouldn’t UTM unless they’re truly different properties.
  • Building short links that include UTMs and then sharing those internally. The shortener doesn’t fix the UTM problem.

FAQ

Does GA4 handle internal UTMs better than Universal Analytics?

Slightly. GA4 has more configurable session timeout rules, but the underlying problem (source overwrite) still exists. Don’t UTM internally.

Can I use a “session_referrer” parameter instead?

Yes — any custom parameter that’s not utm_* is fine. GA4 won’t treat it as a session source.

What about cross-domain tracking?

Configure GA4 cross-domain tracking properly (Admin → Data streams → Configure tag settings). Then no UTMs are needed between your owned domains.

Is this the same problem with Adobe Analytics or Mixpanel?

Adobe — yes, similar issue. Mixpanel — different attribution model, less affected. The general principle holds: don’t manipulate source data on internal traffic.

How do I clean up an account that’s been doing this for years?

You can’t fully — the historical data is corrupted. Strip UTMs from internal links going forward, then look at “first user source” reports rather than session source for cleaner attribution.

Generate clean UTMs for external links only

Use the UTM link generator for emails, ads, and partner placements — places where UTMs belong. Never paste those into your own site’s internal navigation.