Track Button Clicks & Custom Events Without Google Analytics

GA4 makes you learn its event model and a cookie banner to know if a signup button got clicked. Here are the two lines of code that answer that question without either.

By Null Agency · Updated September 7, 2026 · Written for founders and developers who want a yes/no on conversions, not a data warehouse

TL;DR — tracking events without GA4

A pageview tells you someone loaded a URL. It doesn't tell you whether they clicked "Start free trial," submitted a form, or bailed out through an outbound link. That's what a custom event is for, and you don't need GA4's event model, Google Tag Manager, or a cookie banner to record one.

The rest of this guide is the code, the naming convention, and the honest limits — what an event does and doesn't store, and when you actually need GA4 instead.

What a custom event is, and the 3-5 you should actually track

A pageview is automatic: someone requests a URL, the script fires, a row lands in your dashboard. A custom event is deliberate — you decide it matters, you wire it up, and it fires when a specific action happens: a click, a submit, a scroll past a certain point, a JS function completing. Pageviews tell you where people went. Events tell you what they did once they got there. If your dashboard only has pageviews, you can see that your pricing page got traffic — you can't see whether anyone actually clicked "Buy."

Most sites over-engineer this. You don't need thirty events to run a business. You need a short list that maps to the decisions you'll actually make. For the majority of marketing sites, SaaS landing pages, and content sites, five events cover it:

Pick from that list before you write any code. Every event you add beyond it is a maintenance cost with no matching decision behind it — a lesson that applies just as much to measuring basic website traffic as it does to events: more numbers don't automatically produce more insight.

Two ways to fire an event with GhostMetrics

There are exactly two mechanisms, and which one you use depends on whether the action is a plain click or something driven by your own JavaScript.

1. Declarative — for clicks on any element

Add a data-gm-event attribute to any clickable element. GhostMetrics scans the page after DOMContentLoaded and wires up a click listener automatically — no event-name registration, no dashboard configuration step, no code beyond the attribute itself. One limit to know: that scan runs once. Elements added to the page later — by a client-side router or a JS widget — aren't picked up, so use the track() call below for anything that renders after load.

<button data-gm-event="signup-click">Start free trial</button>

That's the entire implementation. The click is recorded with the page path it happened on and any UTM values already in the session. Use this for anything that's a simple click: a CTA button, a nav link, a pricing-tier button.

2. Programmatic — for form submits and JS-driven actions

When the action isn't a plain click — a form submit, a multi-step signup flow, a condition your own code evaluates — call window.ghostmetrics.track() directly. It takes an event name and an optional object where only one key, section, is stored as metadata.

window.ghostmetrics.track('checkout-start', { section: 'pricing' });

Here's that call wired to an actual form submit handler:

<form id="checkout-form" action="/checkout" method="POST">
  <input type="email" name="email" required>
  <button type="submit">Start checkout</button>
</form>

<script>
document.getElementById('checkout-form').addEventListener('submit', function () {
  window.ghostmetrics.track('checkout-start', { section: 'pricing' });
});
</script>

The listener fires the event, then lets the form's own submit proceed normally — no preventDefault(), no waiting on a network callback before the user moves on. The same pattern covers outbound links. GhostMetrics sends via navigator.sendBeacon, which the browser delivers even as the tab navigates away — so this works whether or not the link opens in a new tab:

<a href="https://partner-site.example" target="_blank" rel="noopener external"
   onclick="window.ghostmetrics.track('outbound-click', { section: 'partner-directory' })">
  Visit our partner
</a>

Be honest with yourself about what section is: one short string of context, not a general-purpose properties bag. There is no revenue or value field, and no way to stitch one visitor's checkout-start today to their purchase next week — GhostMetrics events don't carry a cross-session identifier. For a yes/no conversion count, that's the whole job. For a funnel that spans multiple visits, it isn't — more on that in the GA4 section below.

Where events show up, and how to read the UTM breakdown

Every recorded event lands in the dashboard's Custom Events panel, listed by event name with a count and a trend over time. Each event carries the page path it fired on, so if you need the homepage-CTA-vs-blog-button breakdown, export the raw rows (CSV or JSON, every plan) and group by path — the panel itself shows the name, the count, and when it last fired.

Each event also carries whatever first-touch UTM values were present in that visitor's session: utm_source, utm_medium, utm_campaign. These are captured once, at the first pageview of the session, stored in sessionStorage, and attached to every event and pageview that follows in that same tab. Close the tab and the session — and the UTM data with it — is gone. There's no cookie holding it open across visits.

That gives you a real, if bounded, attribution answer — the catch is that you do the joining, not the dashboard. Export the raw event rows (CSV or JSON, on every plan) and group by utm_campaign, and you can say "campaign X produced Y submits this week" without setting a single cookie. What you can't do is attribute an event to a campaign from three weeks ago if the visitor closed their browser in between — that requires a persistent identifier GhostMetrics deliberately doesn't set.

Naming your events so the list stays useful

An event list rots the same way a spreadsheet does: one inconsistent name at a time. A small convention up front keeps five events readable a year later, when a dozen people have touched the codebase.

Privacy: an event is a count, not a person

The reason event tracking usually doesn't need a consent banner comes down to what's actually stored. A GhostMetrics event is a name, a page path, and optionally a UTM value and a section string — a count added to a tally. There's no cookie, no persistent visitor ID, and no identifier that lets you join today's signup-click to next Tuesday's form-submit from the same person. Without that join, there's no individual being tracked across time — just aggregate counts of an action happening.

Cookie banners exist to get consent for non-essential cookies — tracking pixels, cross-site identifiers, anything that lets a site (or an ad network) recognize the same person later. A cookieless event doesn't set any of that, so there's frequently nothing that requires asking permission for. We cover the legal mechanics in more depth in do I need a cookie banner, and the broader cookieless setup — pageviews and events together — in web analytics without a consent banner. Both come with the same caveat this section does: this is general guidance, not legal advice, and it doesn't cover ad pixels, embeds, or other cookie-setting scripts you might also be running.

How Plausible, Fathom, Umami, Matomo and GA4 handle custom events

Every analytics tool with an events feature approaches it a little differently — in how you fire an event, whether "goals" or "conversions" are a separate configurable concept, whether you'll need a cookie banner in the EU, and how the tool is priced. Here's the honest, qualitative comparison.

ToolHow you fire an eventGoals/conversionsEU consent bannerPricing model
GhostMetricsDeclarative attribute or one JS callCustom Events panel, no separate goal configGenerally not required (cookieless)Free-forever single site; flat paid tier for more
PlausibleJS call (plausible('name', {props})) or built-in outbound-link/file-download trackingYes — dashboard Goals tied to events or pageviewsGenerally not required (cookieless)Hosted subscription tiered by pageviews, or self-host free (open source)
FathomJS call (fathom.trackEvent('name'))Yes — dashboard-configurable goalsGenerally not required (cookieless)Hosted subscription tiered by pageviews
UmamiDeclarative attribute (data-umami-event) or JS callBasic event counts; no dedicated funnel builderGenerally not required (cookieless)Free to self-host (open source); hosted plan available
MatomoJS API call or Tag ManagerYes — goals and funnels comparable to GAOften required by default; configurable toward cookielessFree self-hosted (open source) or hosted subscription tiered by traffic
GA4gtag('event', ...) or Google Tag ManagerYes — mark any event as a Conversion, plus Explorations/funnelsYes — sets first-party cookies by default, with ad-platform identity available on topFree with usage limits; paid enterprise tier (GA360)

Where each genuinely wins: Plausible and Umami are the picks if open-source self-hosting or EU-only data residency is a hard requirement. Matomo gets you closer to GA-level funnel depth while keeping the option to self-host. GA4 wins on raw configurability and ad-platform integration once your event tracking needs go beyond counting yes/no actions. For a broader head-to-head, see our GA4 vs Plausible vs GhostMetrics comparison.

When you actually need GA4. If your events need to feed a deep e-commerce funnel — cart adds, checkout steps, refunds, revenue per event, product-level performance — GA4's event model has the fields for that and GhostMetrics doesn't (no value/revenue field, no cross-session funnel). Same story for ad-platform attribution: importing conversions into Google Ads, multi-touch attribution modeling across channels, or feeding Meta/Google's own optimization algorithms all expect GA4's or a tag manager's data structure. If what you need is "did this button get clicked, from which campaign, how often" — the simpler tools above, including ours, are enough. If you need "which a specific order came from which ad, three touches later" — use GA4.

Set up your first events in an afternoon

  1. Start with three of the five (15 min). Pick the three actions that most directly represent intent on your site — for most sites that's signup-click, form-submit, and one of pricing-view, download, or outbound-click.
  2. Add the attributes (20 min). Drop data-gm-event on the buttons and links, and a one-line window.ghostmetrics.track() call into the submit handlers or JS logic that needs it. No Tag Manager container to build, no triggers to configure.
  3. Verify in real time (5 min). Trigger each event yourself — click the button, submit the form, click the link — and confirm it appears in the Custom Events panel immediately. This step catches typo'd event names before they cost you a week of missing data.
  4. Check after a week (10 min). Compare event counts against pageviews on the same pages. A pricing-view count that's a fraction of your pricing page's pageviews, or a form-submit count near zero, usually means the attribute is on the wrong element or the JS never fires — not that nobody's converting.
  5. Export the raw rows (5 min). Once you trust the numbers, pull them out. The dashboard's Export data button gives you every stored event as CSV, or hit the API for JSON — on every plan, including free. Nothing about export is gated behind a paid tier.

That's the whole setup. No consent banner to add because you added events, no Tag Manager to learn, and the same script tag you already use for pageviews is doing the work.

Custom events, no cookie banner: GhostMetrics free-forever

$0 foreverEvents includedNo consent bannerExport on every plan

GhostMetrics is our own cookieless analytics tool, and custom events are part of the free-forever plan — not a paid add-on. Add a data-gm-event attribute or one track() call, and it shows up in the Custom Events panel with the page path and any session UTM attached, no cookie and no consent banner required.

Need more than one site, or a shareable public dashboard? Pro is $9.99/mo flat with a 30-day free trial. Raw event export to CSV or JSON works the same on both plans. See real events fire in the live demo before you decide anything.

Start free — no card, no banner See the live demo

FAQ

What's the difference between a custom event and a pageview?
A pageview fires automatically when a URL loads. A custom event fires when someone does something on that page — clicks a button, submits a form, downloads a file — that a pageview alone can't tell you happened.
Can I track form submissions without Google Tag Manager?
Yes. With GhostMetrics you call window.ghostmetrics.track('event-name', { section: 'context' }) from your own submit handler — no Tag Manager container, no triggers, no publish step.
Does firing custom events require a cookie banner?
Not with a cookieless tool. An event is a count tied to a page and a session, not a cookie tied to a person, so there's usually nothing that requires consent — confirm your own setup, since this isn't legal advice.
What data does a GhostMetrics custom event actually store?
The event name, the page path it fired on, any first-touch UTM values from that session, and — for programmatic events — an optional section string. There's no revenue or value field and no identifier that links events across separate visits.
Can I export my custom events to build my own reports?
Yes, on every plan including free. Use the dashboard's Export data button for CSV, or pull the same rows as JSON from the API.

Keep reading

Do I Need a Cookie Banner?

The consent rules, plainly explained

Analytics Without a Consent Banner

The full cookieless setup, not just events

GA4 vs Plausible vs GhostMetrics

A full head-to-head comparison

GhostMetrics Live Demo

Real events, real dashboard, no signup

Disclosure: GhostMetrics is built by Null Agency and we use it on this site, so we're not a neutral party about our own product — we've kept the claims to what the free and paid plans actually do, and named where GA4, Matomo, Plausible, and Umami fit better. Nothing here is legal advice; confirm your own privacy and cookie obligations for your jurisdiction.