Your podcast host counts downloads. Your newsletter tool counts opens. Neither tells you what happens on your own site after someone clicks an episode link. That gap is what a site analytics tool is for.
A creator site needs three signals: which tagged links brought people to which episode or post, which listen and subscribe buttons they pressed, and which sites send readers unprompted. The audio itself is somebody else's department.
utm_source, utm_medium and utm_campaign on the episode link in your newsletter, your social posts and your show notes. The UTM Breakdown table lists them as source, medium, campaign and visits.data-gm-event="subscribe-click" to Subscribe and Listen buttons. The Custom Events panel shows event name, count and last triggered.A typical independent show has four systems, and each one measures a different thing.
The podcast host serves the audio file and the RSS feed, so it is the only place that can count downloads, per-episode listens and which apps fetched the feed. Apple Podcasts, Spotify and the other directories keep their own listener statistics for their own apps. The newsletter tool (Substack, Beehiiv, Kit, Mailchimp, Ghost and the like) counts sends, opens, link clicks and subscriber growth. A payment or membership tool counts revenue. And your website, the show-notes pages, the archive, the about page, the landing page for a course or a sponsor, is the one surface none of the others can see into.
The model: measure the audio in the host, the email in the newsletter tool, the money in the payment tool, and the site visit in site analytics. Link the layers with UTM tags, because a tag in the URL is the one thing that travels between all of them without any integration.
GhostMetrics is a script on your pages. It sees what a browser does on those pages and nothing else. For a podcast or creator site that gives you a clear list on each side.
It measures: pageviews on every episode page and archive page; the referrer for each pageview; UTM source, medium and campaign from the landing URL; clicks on elements you mark with data-gm-event; calls to window.ghostmetrics.track; how far readers scroll on a page; time on page; country, browser, OS and device class; and real-user Core Web Vitals (FCP, LCP, CLS and TTFB; INP is not captured). On a single-page app, pushState and popstate route changes count as pageviews, so a client-rendered episode list works too.
It does not measure: audio downloads, plays, listen-through rate, RSS subscribers or the apps that fetch your feed. It has no revenue or value field for events, so it cannot report what a sponsor link or a membership signup earned. It does not read data from your newsletter tool, so opens and email clicks stay there. And it will not see clicks inside an audio player embedded from another domain, because the click happens inside the player's iframe and never reaches your page.
The single highest-value habit for a creator is tagging links before they leave your hands. GhostMetrics reads utm_source, utm_medium and utm_campaign from the landing URL. The page URL it records is the path only, so /episodes/42?utm_source=newsletter is counted under /episodes/42, not as a separate page; the tags go into their own columns. utm_term and utm_content are not stored, so do not encode anything you need there.
Because the dashboard groups on exact strings, the scheme matters more than the tool. A pattern that stays readable over dozens of episodes: utm_source is the place the link appears, utm_medium is the kind of placement, and utm_campaign is the episode or issue.
| Where the link lives | utm_source | utm_medium | utm_campaign |
|---|---|---|---|
| Newsletter issue promoting episode 42 | newsletter | ep-42 | |
| Social post announcing the episode | mastodon | social | ep-42 |
| Link in the episode's own show notes, to a guest's site | shownotes | referral | ep-42 |
| Guest's own promo post linking to your page | guest-promo | social | ep-42 |
| Link in a cross-promo swap with another show | swap-showname | podcast | swap-2026 |
| Sponsor landing page link you give an advertiser | sponsor-acme | podcast | spring-run |
Keep everything lowercase, because Newsletter and newsletter are two rows. Use the same campaign string on every placement for the same episode: the point is that ep-42 across all sources lets you compare channels for one episode, and newsletter across all campaigns lets you compare episodes for one channel. The UTM parameters guide goes through naming conventions and common mistakes in more depth.
One honest caveat about how the numbers are counted. The UTM Breakdown counts pageview rows that carry a UTM, grouped by source, medium and campaign, and shows the top 20 combinations. GhostMetrics keeps the first UTM set it sees in a tab and attaches it to the later pageviews in that tab that carry no UTMs of their own. So a reader who lands on episode 42 from your newsletter and then opens two more pages in the same tab adds three rows to the newsletter line. Read the "visits" column as tagged pageviews, and compare the newsletter's share across weeks, not as a headcount. A page whose URL carries its own different UTMs reports those, not the stored ones.
Nothing carries over between sessions. The stored UTM lives in sessionStorage and clears when the tab closes, so a listener who clicks your newsletter link on Monday and returns on Thursday from a bookmark is a new session with no attribution. For a show whose audience returns weekly, that means the UTM table measures first arrivals from your tagged links, not loyalty. That is by design: there is no cross-session identifier.
A creator site usually has a short list of actions that matter: subscribe to the newsletter, listen on a platform, follow the show, support it, book a guest slot. Each can be one event. Add the attribute to the element and clicks are recorded; no JavaScript is needed.
<a href="https://podcasts.apple.com/..." data-gm-event="listen-apple">Listen on Apple Podcasts</a>
<a href="https://open.spotify.com/..." data-gm-event="listen-spotify">Listen on Spotify</a>
<a href="/feed.xml" data-gm-event="listen-rss">RSS feed</a>
<button type="submit" data-gm-event="subscribe-click">Subscribe</button>
A few facts about how this behaves, each of which affects how you name things:
data-gm-event. A button inside a card that is also marked will record two events for one click, so mark one level only.listen-apple, listen-spotify) instead of reusing one listen-click name and hoping to split it later.For something that is not a click, such as a form that submitted successfully, call the function from your code:
window.ghostmetrics.track('subscribe-success', { section: 'footer-form' });
Only section is stored as metadata, and it is only sent through track(); the data-gm-event attribute sends the name, path and UTM. There is no numeric value, so a sponsor click is a count, not a dollar figure. And a click on a Subscribe button is an intent signal, not a confirmed subscription: if the form validates on the server, the number of events can exceed the number of new subscribers. Your newsletter tool holds the real subscriber count. The custom events guide has naming patterns that keep the panel readable as the list grows.
The Referrers table lists the referrer string the browser supplied for each pageview, top 20, with visits and share. Alongside it, the Traffic Type donut buckets the same rows into search, social, direct and referral. For a creator, the table is the useful half, because it shows names: which blog quoted you, which forum thread carried a link, which aggregator picked up an episode.
Three things to know before reading it:
The All Pages table lists page URL, views, average scroll, average time and bounce rate for your top 50 pages in the selected period. For a podcast site, sort by views to see which episode pages draw the most traffic, then read the engagement columns.
Two details change how to read them. First, average scroll and average time come only from pages where the leave beacon arrived, which fires when the tab is first hidden or the page unloads. Time on page is measured from load to that first hide. A reader who starts an embedded player and switches to another app stops the clock when the tab goes to the background, so show-notes pages with long audio tend to read short on time. That is a property of the measurement, not a sign nobody listened. Second, bounce rate counts a single-page session in that tab, the classic definition. A show-notes page can be a perfectly good one-page visit: the reader came for the guest's link and left. Do not treat a high bounce on an episode page as a failure by itself.
What works better for episodes:
The install is one tag. This is the whole procedure on any host.
<head>, in the shared layout or header injection field, so every page inherits it. On Ghost the place is Settings, Code injection, Site header. On a static generator it is the base layout. The snippet is below.data-gm-event to each.<head>
<!-- ...your existing tags... -->
<script defer src="https://ghostmetrics.nullagency.io/gm.js" data-site="YOUR-SITE-ID"></script>
</head>
If a hosted publication platform does not let you add custom scripts to your pages, no script-based tool can run there. Some platforms allow code injection on certain plans and others do not, so check the platform's current docs. The fallback is to measure the publication in its own dashboard and point readers to a page on a domain you control for anything you want to measure.
GhostMetrics sets no cookies, uses no localStorage, stores no IP addresses (they are hashed) and keeps no cross-session identifier. Its only browser storage is sessionStorage in the tab, holding a pageview counter and any first-touch UTM, and it clears when the tab closes. Global Privacy Control and Do Not Track are honored, which means nothing is collected for those visitors. Consent for cookie-based tools is generally required in the EU and UK, which is why many creators using a cookieless tool run no banner. The page itself may still need one if you embed a player, an ad network or a social widget that sets its own cookies; those have their own rules, and do I need a cookie banner walks through the cases. For the analytics side, web analytics without a consent banner covers the reasoning.
These four cover most of what a creator shortlists for the website side. None of them replaces a podcast host's download statistics.
| Tool | Price model | Hosting | Cookieless | Custom events | UTM breakdown | Export |
|---|---|---|---|---|---|---|
| GhostMetrics | Free plan for one site, unlimited pageviews, no card. Pro $9.99/mo flat for more sites and a public dashboard | Hosted only, not open source | Yes | Yes (data-gm-event or ghostmetrics.track) | Yes (source, medium, campaign) | CSV or JSON of raw rows, every plan |
| Cloudflare Web Analytics | Free | Hosted only, not open source | Yes | No | No | No CSV button; GraphQL Analytics API |
| Plausible | No free plan; free trial, then paid plans tiered by monthly pageviews (check current pricing) | Hosted (EU) or self-hosted Community Edition; open source | Yes | Yes | Yes | Yes (check current docs for formats) |
| Umami | Free to self-host (you pay for the server); Umami Cloud is the hosted option, check current pricing | Self-hosted or Umami Cloud; open source (MIT) | Yes | Yes | Yes | Full database if self-hosted |
Cloudflare Web Analytics is free and good enough for a pageview count and a referrer list, particularly if the site is already proxied through Cloudflare. For a creator it stops at the two features this page is about: no custom events (no way to count the Listen button) and no UTM breakdown (no way to see which tagged link won). More in Cloudflare Web Analytics alternatives.
Plausible is the right pick if open source or EU-only processing is a requirement, and it ships an official WordPress plugin, which GhostMetrics does not. It has no free plan, so even a small show pays once the trial ends. Details in Plausible alternatives.
GhostMetrics is ours, so weigh this accordingly. It combines a free hosted plan, custom events, a UTM breakdown and real-user Core Web Vitals in one script. The tradeoffs: one site on the free plan (Pro covers unlimited websites, fair-use ceiling of 250), no open source, no self-hosting, no WordPress plugin (you paste the tag into the head), and no session recordings, heatmaps, A/B tests or emailed reports.
Be clear about the limits before you commit. If you sell through a funnel with ads, GA4's Google Ads attribution, audiences and ecommerce reporting are genuine strengths that a cookieless tool does not copy. If sponsors pay on verified downloads, you need your host's download statistics and nothing on your website will substitute. If you want to follow one listener from first episode to paid membership across months, no cookieless tool will do that by design: attribution here is first-touch within a single tab session. And if your pages live on a hosted publication that blocks third-party scripts, the answer is the platform's own analytics.
GhostMetrics is cookieless web analytics with one script tag, about 3 KB compressed, and no cookies, no localStorage and no stored IP addresses. The free plan is free forever with no card: one site, unlimited pageviews, the real-time dashboard, every view, full history, plus raw CSV or JSON export on every plan. We use it on nullagency.io.
Need more than one site or a public dashboard URL? Pro is $9.99/mo flat with unlimited websites (fair-use ceiling of 250) and a 30-day free trial; a card starts the trial, nothing is charged for 30 days, and you can cancel anytime. Mark a button with data-gm-event="listen-spotify" or call window.ghostmetrics.track('subscribe-success', { section: 'footer-form' }) from code.
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 pointed to Plausible, Umami and Cloudflare Web Analytics where they genuinely fit better. Pricing for third-party products can change; always check the vendor's current pricing page before deciding.