Track Outbound Link Clicks Without Google Analytics in 2026

A pageview tool tells you who arrived. It says nothing about which link they left through. Two ways to count outbound clicks with no cookies, no Tag Manager and no consent banner, plus the naming rules that keep the data usable.

By Null Agency · Updated October 16, 2026 · Written for site owners who need to know which affiliate, partner, docs or social links actually get clicked

TL;DR: tag the link, name the event, read the count

An outbound click is a custom event. A cookieless analytics tool counts the pageview when someone lands; leaving through a link is a separate action you have to ask it to record.

If you only need the code, jump to the two methods below. If you are deciding whether this is worth doing, start with what you cannot see today.

What a pageview tool cannot see about exits

Every analytics dashboard has an exit-pages report. It tells you the last page of a session: the page a visitor was on before they closed the tab or went somewhere else. It does not tell you which link took them there, or whether they left through a link at all. A visitor who closes the tab and one who clicks your partner link look identical in that report.

That gap matters on pages whose job is to send people elsewhere. Affiliate recommendations, a "view source on GitHub" link, a sponsor logo, a link to your app store listing, a booking page on a third-party scheduler, a docs page pointing at an external API reference. On these pages the outbound click is the conversion, and a pageview count alone cannot grade them. Two articles with identical traffic can send very different numbers of people to the same partner, and only a click event shows the difference.

The same applies in reverse for editorial decisions. If a resources page lists twenty external links, the click counts tell you which five earn their place and which fifteen are padding. That is a better editing signal than scroll depth alone, and the two combine well: a reader who reached the bottom of the page and clicked is a different reader from one who bounced at the headline.

Google Analytics 4 can log some outbound clicks automatically through its enhanced measurement setting; check current GA4 docs for exactly which clicks it counts and what it reports. The price of that convenience is the usual one: cookies by default, so consent is generally required for EU and UK visitors, and a heavy script. This guide covers the cookieless route, where you opt each link in and keep a tiny script. For the broader pattern of events without GA, see how to track custom events without Google Analytics.

Method 1: the declarative attribute

The simplest approach needs no JavaScript of your own. Add data-gm-event to the anchor and give it a name:

<a href="https://github.com/your-org/your-repo"
   data-gm-event="outbound-github"
   rel="noopener">View the source on GitHub</a>

GhostMetrics installs one delegated listener on the document. It reads the attribute at click time, so it does not matter when the link was created. Links in server-rendered HTML work. So do links rendered after load by a client-side router, a comment widget, a modal or a lazy-loaded section. There is nothing to re-bind after a route change and no scan that runs once and misses late elements.

Three practical notes. First, put the attribute on the link itself; if your link wraps an icon and text, clicking either still counts because the listener walks up from the clicked element. That walk records every tagged ancestor, so do not tag both a card and a link inside it, or one click becomes two events. Second, the attribute records the event name only; a section value needs the programmatic call below. Third, you can put the attribute on non-link elements too, such as a button that opens an external URL through JavaScript, so you can use the same convention for "Buy on Amazon" buttons and plain text links.

This method is the right default for editorial sites, docs and landing pages. A content editor can tag a link in the CMS by adding an attribute, without a deploy and without asking an engineer. It is also easy to audit: a search for data-gm-event="outbound- in your repository or page source lists every tracked exit.

Method 2: the programmatic call

When the click needs logic around it, call the tracker yourself. The API is one function:

window.ghostmetrics.track('outbound-click', { section: 'pricing-footer' });

The first argument is the event name. The second is optional metadata, and only section is stored; any other keys you pass are ignored. Use it for placement ("header", "footer", "sidebar", "inline") so you can tell whether the same destination performs better in one slot than another.

Programmatic calls earn their keep in three cases: links generated from data (a list of 200 tool links rendered from JSON), links where you already have a click handler, and rules that apply to a whole class of links. The last one is the common request, "count every external link without tagging each one". Here is a small handler that does it:

document.addEventListener('click', function (e) {
  var a = e.target.closest && e.target.closest('a[href]');
  if (!a || a.closest('[data-gm-event]')) return;    // already tracked
  var url;
  try { url = new URL(a.href, location.href); } catch (err) { return; }
  if (!/^https?:$/.test(url.protocol)) return;       // skip mailto:, tel:
  if (url.origin === location.origin) return;         // skip internal links
  if (window.ghostmetrics) {
    window.ghostmetrics.track('outbound-click', { section: url.hostname });
  }
});

This records a single event name, outbound-click, and puts the destination hostname in section. The guard on data-gm-event prevents double counting when you have also tagged a link, or an element around it, by hand. The trade-off is where the hostname lives. The Custom Events panel groups by event name, so you will see one row, outbound-click, with a total. To split it by destination you read the raw export, where each row carries its section value; the manifest.json that ships with the export describes every column.

That is why the two methods are complementary. Use the attribute for the handful of links you care about by name (the sponsor, the app store, the signup on a partner site) so they show up as their own rows in the dashboard. Use the catch-all handler as a net underneath, and analyze the long tail in a spreadsheet.

Naming conventions that survive a year of data

Event names are the only thing the dashboard groups by, so they are your schema. Names invented ad hoc by three people over twelve months produce a panel full of near-duplicates. A convention costs nothing and fixes this up front. A workable scheme:

GoalEvent namesection valueWhere you read it
Affiliate link to one merchantoutbound-merchant-namereview-table or inlineCustom Events row; section split in export
Source code linkoutbound-githubheader or footerCustom Events row
Social profile linksoutbound-socialx, linkedin, youtubeOne row; platform split in export
Third-party booking pageoutbound-bookingpricing or contactCustom Events row
Every external link, untaggedoutbound-clickdestination hostnameExport grouped by section

A section value only exists when the event is sent with window.ghostmetrics.track(); a link tagged with the attribute alone records the name and the page.

Keep the named list short. Fifteen named exits is a dashboard you can read; two hundred is a spreadsheet, and the catch-all method plus the export handles that better. A good rule: name an exit if you would act on its count, and let the catch-all cover the rest.

How to set it up and verify it in about twenty minutes

Do this once per site. The steps assume the GhostMetrics tag is already in your <head>; if it is not, adding analytics to a static site covers the one-line install for most hosts.

  1. List the exits worth counting. Open your top ten pages by traffic and write down every external link on them. Cross off navigation, footers and legal links you would never change. What is left is your candidate list.
  2. Pick names with the scheme above. Write the list as a table: link, event name, section. Commit it to your repository or a shared doc so the next editor reuses names.
  3. Tag the links. Add data-gm-event to each anchor. If you use a CMS with a link dialog that cannot add attributes, switch that block to an HTML embed, or use the catch-all handler and read the export.
  4. Add the catch-all handler if you want the long tail. Paste the snippet from Method 2 once, in a site-wide script that loads after gm.js. Leave the guard on data-gm-event in place.
  5. Test from a clean browser tab. Open your own site, click a tagged link, and confirm the event appears in the dashboard's Custom Events panel with the name you chose and a recent last-fired time. Test one link in each placement, and one link rendered by JavaScript if you have any.
  6. Test with privacy signals on. GhostMetrics honors Global Privacy Control and Do Not Track by collecting nothing, so a browser with either enabled will not show up in your test. If your clicks vanish, check those settings before you debug the markup.
  7. Wait a full week, then read it. Compare the click count against pageviews of the page that hosts the link. That ratio, clicks per pageview, is the number to track over time.

Step 6 catches the most confusing false alarm: your own browser blocking your own test. It is also a reminder that a cookieless tool still respects explicit opt-out signals, so the counts reflect visitors who did not send one.

How to read the numbers without fooling yourself

A raw click count is nearly useless on its own. Three comparisons make it informative.

Clicks per pageview of the hosting page. If outbound-merchant-name fired 40 times and the review page had 1,000 pageviews, the link converts at 4 percent of views. The same 40 clicks on a page with 10,000 views is 0.4 percent, which is a layout problem, not a success. The Top Pages report gives you the denominator; the Custom Events panel gives you the numerator.

Clicks by source. Events carry the session's first-touch UTM source, medium and campaign, so a newsletter campaign that sends 300 visits and 45 partner clicks can be told apart from organic traffic that sends 300 visits and 6 clicks. The dashboard panel shows event name, count and last fired; to cut clicks by campaign, group the raw CSV by utm_campaign. Consistent UTM naming is what makes that grouping work; see the UTM parameters guide.

Clicks against scroll depth. The pages table shows the average scroll depth of the hosting page. If a link sits near the bottom of a page that readers typically leave halfway down, moving the link up is a cheaper fix than rewriting the paragraph around it. Scroll depth is recorded per pageview and clicks are separate events, so treat this as a page-level comparison, not a match of the same visits.

One more habit: look at the week-over-week trend, not a single day. Small sites see click counts in the single digits per link per day, and a swing from 3 to 6 is noise. Wait for enough volume that the comparison means something, and do not redesign a page on twelve clicks.

Honest limits of cookieless click tracking

Every tool makes trade-offs. These are the ones you will notice.

Know which gestures count. The tracker listens for the browser's click event: a normal click, Ctrl or Cmd-click and pressing Enter on a focused link all fire it, and the beacon is queued with sendBeacon before the browser navigates. A middle-click and "Open link in new tab" from the context menu do not fire click, so they are not counted. Test your own critical links in the browsers your readers use and compare against a partner-side count before you rely on a number for a payout decision.

How the main tools handle outbound clicks

The point of this table is the mechanism, not a feature checklist. Where a detail changes with plans or versions, check the vendor's current docs.

ToolOutbound clicksCookies / consentWhere the data goes
GhostMetricsOpt in per link with data-gm-event, or track() from code; no automatic detectionNo cookies, no localStorage; honors GPC and DNTCustom Events panel; raw CSV/JSON export on every plan
Google Analytics 4Enhanced measurement can log outbound clicks automatically; check current docs for what it recordsCookies (_ga) by default; consent generally required in the EU/UKReports, explorations, free BigQuery export; thresholding can apply
PlausibleOffers outbound link tracking as an opt-in script option; check current docsCookielessGoals and custom properties; check current docs
UmamiCustom events through a data attribute or a function callCookielessEvents view; full database if self-hosted
Cloudflare Web AnalyticsNo custom eventsCookielessNot available for click tracking

GA4 wins on automatic coverage and on tying clicks to Google Ads audiences if you run paid campaigns; that is a legitimate reason to keep it. If you want the cookieless version of the same measurement, with an attribute you control and no banner, see Google Analytics alternatives for the wider field, and analytics without a consent banner for what removing the banner involves.

Count exits with one attribute, no cookies, no banner

~3 KB script$0 forever1 site free$9.99/mo flat Pro

GhostMetrics is cookieless web analytics we run on this site. Install one script tag and add data-gm-event to the links you care about. The free plan is free forever: one site, unlimited pageviews, real-time dashboard, every view, full history, including the Custom Events panel.

Need more sites or a public dashboard? Pro is $9.99/mo flat, unlimited pageviews, unlimited websites (fair-use ceiling of 250), with a 30-day free trial; a card starts the trial, nothing is charged for 30 days, and you can cancel anytime. Raw event export as CSV or JSON is on every plan, including free, so your click data is always yours to group and chart.

Start free, no card See the live demo

FAQ

Does GhostMetrics track outbound link clicks automatically?
No. Pageviews are automatic, but an outbound click is a custom event you opt into: add data-gm-event to the link, or call window.ghostmetrics.track() from a click handler. GA4's enhanced measurement can log outbound clicks without tagging each link, so that is a real convenience difference.
Is the destination URL stored with the click?
No. An event stores its name, the page path it fired on, any session UTM values, and an optional section string. Put the destination in the event name (outbound-github) or in the section value, and keep the list of destinations short.
Can I count clicks on a link inside a modal or a client-rendered component?
Yes for data-gm-event. GhostMetrics uses one delegated document listener, so links rendered after page load by a router, widget or modal are tracked without re-binding anything.
Do outbound click events need a cookie banner?
GhostMetrics sets no cookies and stores no localStorage, IP address or cross-session identifier, so an event is a count tied to a page and a tab session. Consent rules depend on your jurisdiction and setup; this is not legal advice.
Can I see which people clicked which link?
No, by design. There is no visitor ID, so you see how many clicks a link got, not who clicked. The raw CSV or JSON export, available on every plan, lets you group clicks by page path, event name and campaign.

Keep reading

Custom Events Without GA

Buttons, forms and downloads, with code

UTM Parameters Guide

Naming rules that make click data sortable

Scroll Depth Tracking

The other half of engagement: how far people read

GhostMetrics Live Demo

The real dashboard, live data

Disclosure: GhostMetrics is built by Null Agency and we use it on this site, so we are not a neutral party about our own product. We kept the claims to what the free and paid plans do, and pointed to GA4 where its automatic outbound tracking and ads integration genuinely fit better. Third-party features and pricing change; check each vendor's current docs before deciding.