To track link clicks in GA4, you've got two routes: turn on enhanced measurement, which sends a click event for outbound links and file_download for files, or build a Click - Just Links trigger in Google Tag Manager and send your own event with the parameters you choose. Enhanced measurement covers the basics for free. GTM covers everything it misses: internal CTAs, mailto: and tel: links, button labels, and where on the page the click happened.

The trick is knowing where one ends and the other begins. Get it wrong and you'll either miss half your clicks or count the same click twice, in two different event names, forever.

Key Takeaways
  • Enhanced measurement sends click (with outbound, link_url, link_domain) only for links to other domains. Internal links and most mailto: / tel: links are invisible to it.
  • For anything else, use Triggers > New > Click - Just Links in GTM, plus the built-in Click URL and Click Text variables.
  • Don't name your GTM event click or file_download. Google lists both as reserved event names for web. Use something like link_click or contact_click.
  • If GTM and enhanced measurement both track outbound links, you get two events per click. Pick one owner per link type.
  • Test in GTM Preview and GA4 DebugView, then register custom parameters as custom dimensions, or they won't show up in reports.

What GA4 tracks on its own (and what it quietly skips)

Enhanced measurement lives in Admin > Data streams > your web stream > Enhanced measurement (the gear icon). Two toggles matter here.

Outbound clicks fires the click event "each time a user clicks a link that leads away from the current domain", in Google's words. It sends link_classes, link_domain, link_id, link_url and outbound (a boolean). Links to domains you've listed for cross-domain measurement don't count as outbound. That's by design.

File downloads fires file_download when the link points to a file matching Google's extension regex: pdf|xlsx?|docx?|txt|rtf|csv|exe|key|pp(s|t|tx)|7z|pkg|rar|gz|zip|avi|mov|mp4|mpe?g|wmv|midi?|mp3|wav|wma. Parameters: file_extension, file_name, link_text, link_url, plus classes and ID.

Notice what's missing. No internal links. No "Book a call" button that goes to /contact. No .webp or .json downloads.

And in my experience, mailto: and tel: links don't show up as outbound clicks reliably enough to report on. I don't trust enhanced measurement for contact links at all.

Here's the comparison I give clients:

What you want to track Enhanced measurement GTM Just Links trigger
Outbound links to other domains Yes, click event Yes, if you build it
Internal CTA links (/pricing, /contact) No Yes
mailto: and tel: links Don't rely on it Yes
PDF, DOCX, ZIP downloads Yes, file_download Yes
Unusual file types (.webp, .json, .ics) No Yes, with your own regex
Link text as a parameter Only for downloads Yes, via Click Text
Where on the page (header, footer, article) No Yes, with a small extra variable
Effort One toggle 20-40 minutes per setup

For a small brochure site with five outbound partner links, the toggle is fine. For anything where a click is a lead signal, I build it in GTM.

Why I stopped trusting the toggle for contact links

Paulina runs a physiotherapy clinic chain with four locations around Poznań. Her agency reported "phone clicks" from GA4 for over a year, and the number looked healthy: 310 a month. Then the clinic switched call tracking providers and the call log showed 1,140 calls started from the website in the same month.

The GA4 number wasn't phone clicks. It was the click event, filtered by "contains tel" on a dimension that only some of the clicks carried. On mobile Safari, a chunk of tel: clicks never produced an event at all. Nobody had checked, because the number moved up and down like a real metric.

I rebuilt it in GTM in one afternoon: one Just Links trigger for tel:, one for mailto:, one GA4 event tag called contact_click with a contact_method parameter. The next month GA4 showed 1,062 contact_click events with contact_method = phone. Not 1,140, because some people dialed the number by hand after reading it. Close enough to plan budgets on.

That's the lesson. A plausible number is more dangerous than a missing one.

How to track link clicks in GA4 with GTM, step by step

This assumes you already have a Google tag (your GA4 measurement ID) in the container. If GTM itself is new to you, start with what Google Tag Manager is and how it works, then come back.

Step 1: Turn on the built-in Click variables

Go to Variables > Built-In Variables > Configure, and tick everything in the Clicks section: Click Element, Click Classes, Click ID, Click Target, Click URL, Click Text. They're off by default in a new container. If you skip this, your trigger condition dropdown won't even show Click URL.

Step 2: Create a hostname variable for the clicked link

Click URL gives you the full href. For outbound logic, you want just the hostname.

Variables > User-Defined Variables > New > URL. Set Component Type to Host Name, tick Strip 'www.', and under More Settings change URL Source from Page URL to {{Click URL}}. Name it URL - Click Hostname.

This one variable saves you from fragile "Click URL does not contain mysite.com" conditions that break the day someone links to mysite.com.evil-redirect.net. Hostname matching is exact, substring matching is not.

Step 3: Build the trigger

Triggers > New > Trigger Configuration > Click - Just Links. You'll see two checkboxes:

  • Wait for Tags: GTM holds the navigation until your tags fire or the timeout passes. Default max wait is 2000 milliseconds. It only matters for links opening in the same tab.
  • Check Validation: the trigger fires only when the click is a "valid action", meaning nothing else on the page cancelled the default link behavior. Leave it unticked if your site uses JavaScript routers or preventDefault() on links, or the trigger will never fire.

If you tick either, GTM asks Enable this trigger when. Set it to Page URL matches RegEx .* unless you want to limit it.

Then This trigger fires on: Some Link Clicks, with conditions. Three triggers I use on almost every site:

  1. Outbound: URL - Click Hostname does not match RegEx (^|\.)example\.com$ AND Click URL starts with http
  2. Phone: Click URL starts with tel:
  3. Email: Click URL starts with mailto:

Step 4: Create the GA4 event tag

Tags > New > Tag Configuration > Google Analytics > Google Analytics: GA4 Event. Fill in your measurement ID, then:

  • Event Name: link_click for outbound, contact_click for phone and email
  • Event Parameters:
  • link_url = {{Click URL}}
  • link_text = {{Click Text}}
  • link_domain = {{URL - Click Hostname}}
  • contact_method = phone or email (on the contact tag only)

Attach the matching trigger. One tag per event name keeps reports clean. I'd rather have three small tags than one clever tag with a Lookup Table nobody understands six months later.

Step 5: Preview, test, publish

Click Preview, open your site, click a link. More on testing below, because this is where most setups fail quietly.

Tracking mailto, tel and downloads without the mess

Contact links deserve their own event. They're not "outbound traffic", they're intent. If you lump tel: into a generic link_click, someone will build a report on outbound partner clicks and accidentally include 400 phone calls.

A few specifics that bite people:

  • Click Text on icon links is empty. A phone icon with no visible text gives you link_text = "". Add a link_location parameter instead, built from a DOM attribute like data-location="header" or from the closest section. A Custom JavaScript variable reading {{Click Element}}.closest('[data-location]') works if devs add the attribute.
  • Downloads beyond the default list. If you host .ics calendar files or .webp assets people actually save, build a Just Links trigger with Click URL matching RegEx \.(ics|webp|json)(\?|$) and send file_download_custom, not file_download.
  • Parameter values cap at 100 characters. Google's limit for event parameter values on standard properties is 100 characters. A long signed download URL gets cut. Strip query strings with a URL variable if they're noise.
// Custom JavaScript variable: link location from the nearest data attribute
        function() {
          var el = {{Click Element}};
          if (!el || !el.closest) return 'unknown';
          var box = el.closest('[data-location]');
          return box ? box.getAttribute('data-location') : 'body';
        }
        

Avoiding double counting with enhanced measurement

Marcin manages marketing for a SaaS reseller in Kraków. His Looker Studio report showed partner link clicks jumping from roughly 900 to 1,850 a month, overnight, right after a freelancer "added proper link tracking in GTM". Partners were thrilled. Marcin wasn't, because demo requests didn't move at all.

Both systems were firing. Enhanced measurement sent click with outbound = true. The new GTM tag sent outbound_click for the same links.

The Looker report summed both event names because the filter was "event name contains click". Every outbound click counted twice.

Two clean ways out:

  1. GTM owns outbound links. Turn off the Outbound clicks toggle in enhanced measurement. Your GTM tag becomes the single source.
  2. Enhanced measurement owns outbound, GTM owns the rest. Keep the toggle, and scope your GTM triggers only to internal CTAs, tel: and mailto:.

I'll be blunt: option 1 is almost always better. You control the parameters, you can add link_location, and you can see the logic in a container version history. A toggle in a GA4 admin screen gives you none of that.

And never name your GTM event click. Google's event naming rules list click, file_download, scroll, video_start and video_progress as reserved names for web. Even if a hit gets through, you've mixed two sources into one event name and you'll never untangle them in reports.

Testing in Preview and DebugView

Preview mode first. Click a link on your site, then look at the Tag Assistant panel on the left. You should see a Link Click event (the data layer name is gtm.linkClick). Select it and check:

  • Tags tab: your GA4 - link_click tag under "Tags Fired". If it sits under "Tags Not Fired", open it and see which trigger condition failed.
  • Variables tab: Click URL, Click Text and your hostname variable hold what you expect. An empty Click Text here means an empty parameter in GA4.

A classic trap: links that open in a new tab with target="_blank" are easy to test. Same-tab links unload the page before you can look. Hold Ctrl or Cmd when clicking, or tick Wait for Tags while testing.

Then open GA4 Admin > DebugView. Your link_click event should appear within seconds, with its parameters listed.

If it's in Preview but not DebugView, check consent. With analytics_storage denied, what reaches GA4 depends on your consent mode setup. My GA4 debug mode guide covers the cases where DebugView stays empty for no obvious reason.

Registering parameters as custom dimensions

Your event will show up in Reports > Engagement > Events within 24-48 hours. The parameters won't, unless they map to a dimension GA4 already has.

GA4 ships predefined dimensions for enhanced measurement parameters: Link URL, Link domain, Link text, Outbound, File name, File extension. Your own parameters, like link_location or contact_method, need registering. Admin > Data display > Custom definitions > Create custom dimension, scope Event, and type the exact parameter name.

Three rules I follow:

  • Register only what someone will filter by. A standard property gets 50 event-scoped custom dimensions, and they go faster than you think.
  • Data appears from the moment you register, not retroactively. Register on day one.
  • Match names exactly. Link_Location and link_location are two different things to GA4.

The full walkthrough, including the limits per property type, is in the GA4 custom dimensions guide. If your link data should come from the site itself rather than DOM scraping, the GA4 data layer and GTM guide shows how to push it cleanly.

Frequently asked questions

Does GA4 track link clicks automatically? Only outbound ones, through enhanced measurement, as a click event with outbound, link_url and link_domain. Internal links and CTAs aren't tracked at all. For those you need a GTM trigger or custom code.

What's the difference between Click - All Elements and Click - Just Links? Just Links listens only to clicks on <a> elements and returns the link's href as Click URL, even if the user clicked a <span> inside it. All Elements fires on any click and returns details of the exact element clicked. For links, Just Links gives you cleaner data.

How do I track mailto and tel clicks in GA4? Create a Just Links trigger with Click URL starting with mailto: or tel:, then a GA4 Event tag with a custom name like contact_click. Add a contact_method parameter and register it as a custom dimension so you can split email from phone.

Why does my link click tag fire twice? Usually either enhanced measurement and GTM both track the same links, or two triggers match the same click. Check Preview for two tags firing on one Link Click event, and check whether the Outbound clicks toggle is still on.

Should I tick Wait for Tags? For same-tab links that leave your site, yes, it gives the hit time to send before the page unloads. The downside is up to 2 seconds of delay if something hangs. For new-tab links it does nothing useful.

Can I name my GTM event "click"? I wouldn't. Google lists click as a reserved event name for web streams. Use a name of your own like link_click, keep it lowercase with underscores, and stay under 40 characters.

Next steps

Open your GA4 property today and check two things: is the Outbound clicks toggle on, and does any GTM tag also track outbound links? If both are true, you're counting twice. If neither covers tel: and mailto:, you're missing your highest-intent clicks entirely.

Fix the ownership question first. Then build the three triggers above, test them in Preview, and register contact_method before you need it.

If you'd rather have someone go through the container and tell you exactly which clicks are double counted, which are missing, and which "phone clicks" metric is fiction, the free GTM audit does that. For ongoing checks that catch it when a redesign breaks your triggers, see the GTM monitoring retainer.


Sources and further reading - Enhanced measurement events (Google Analytics Help) - Click trigger (Tag Manager Help) - Built-in variables for web containers (Tag Manager Help) - Event naming rules (Google Analytics Help)

Not sure which of your link clicks GA4 is actually counting?

The free GTM audit checks your click triggers, duplicate events and enhanced measurement settings, and tells you what is double counted or missing.

Start Free GTM Audit
Piotr Litwa

Piotr Litwa

GTM & Analytics Specialist

Piotr monitors GTM containers and GA4 properties for businesses across Europe, catching tracking issues before they cost you conversions. 120+ clients, 10+ years, zero outsourcing.