Category: Analytics

  • Traffic analytics tools count bots as visitors—here’s the filter math

    Traffic analytics tools count bots as visitors—here’s the filter math

    Traffic analytics tools count bots as visitors—here's the filter math
    Photo: Saleemkce via Wikimedia Commons (CC BY-SA 4.0)

    If your analytics dashboard shows 10,000 monthly visitors, somewhere between 15% and 40% of that number is probably bots. Not malicious traffic—just crawlers, monitoring services, SEO tools, and automated scrapers that ping your site without any human behind them.

    Most analytics platforms count these as real visitors by default. And unless you’ve configured filters, you’re making decisions based on inflated numbers.

    Why analytics tools count bots in the first place

    Client-side analytics tools like Google Analytics 4, Plausible, and Fathom fire a JavaScript snippet when a page loads. If the bot renders JavaScript, the analytics event fires. If it doesn’t, the request still shows up in server logs—and server-side analytics tools count it.

    Google Analytics 4 has built-in bot filtering, but it’s not comprehensive. It blocks known bots from the IAB/ABC International Spiders and Bots List, which covers major crawlers like Googlebot and Bingbot. But it misses:

    • Uptime monitors (Pingdom, UptimeRobot, StatusCake)
    • SEO crawlers (Ahrefs, Semrush, Moz)
    • Social media preview scrapers (LinkedIn, Slack, Discord)
    • Headless browser automation (Playwright, Puppeteer scripts)
    • RSS feed readers that also fetch the full page

    Each of these shows up as a pageview. Some trigger multiple events per visit if they follow internal links.

    How to spot bot traffic in your current numbers

    Three signals tell you bots are inflating your counts:

    Abnormally high bounce rate on specific pages. If a page shows 95%+ bounce with an average session duration under three seconds, you’re likely looking at bot traffic. Uptime monitors hit the homepage and leave. SEO crawlers fetch a page, extract the content, and exit.

    Traffic spikes at regular intervals. Check your hourly traffic distribution. If you see consistent spikes every hour, every six hours, or every day at the same time, that’s automated monitoring. Human traffic clusters around working hours in your audience’s timezone.

    Zero scroll depth and instant exits. Platforms that track scroll depth (Hotjar, Microsoft Clarity, Fathom’s newer builds) show bots as 0% scroll. If a page shows hundreds of visits with zero engagement and no scroll, filter those out manually or via segments.

    The filtering options that actually work

    Server-side filtering is more reliable than client-side. If you control your web server or use a reverse proxy like Cloudflare, you can block bot traffic before it reaches your analytics tool.

    In Google Analytics 4, enable bot filtering under Admin → Data Settings → Data Filters → Internal Traffic. You’ll need to define internal traffic by IP or user agent. The built-in bot filter is already on by default, but it’s not enough—add custom filters for known monitoring services.

    In Plausible, bot filtering is automatic and more aggressive than GA4. The platform blocks traffic from data centers, known crawlers, and requests without a referrer or with suspicious user agents. You can’t customize it, but the default works well for most solo operators.

    Fathom takes a similar approach: automatic filtering with no configuration required. It excludes bot traffic by checking for JavaScript execution, referrer presence, and IP reputation. Unlike Plausible, Fathom also filters out traffic from VPNs and known hosting providers by default, which can occasionally exclude real users—but keeps bot counts low.

    For self-hosted analytics (Matomo, Umami, Ackee), you’ll need to configure exclusions manually. Most support regex-based user agent filtering. A starter list:

    • bot|crawler|spider|scraper|headless|phantom|selenium
    • uptimerobot|pingdom|statuscake|newrelic
    • ahrefsbot|semrushbot|mj12bot|dotbot|blexbot

    Test your regex in a staging environment first—you can accidentally block legitimate traffic if you’re too broad.

    What the real numbers tell you

    After you filter bots, expect your visitor count to drop by 15–40%. For sites with heavy SEO tool activity or uptime monitoring, the drop can hit 50%.

    That’s not a problem. It’s clarification.

    Your engagement metrics—time on page, scroll depth, conversion rate—will improve because you’re no longer averaging in zero-second bot visits. If your conversion rate was 2% before filtering and 3.2% after, you didn’t suddenly get better at writing CTAs. You just removed the denominator noise.

    One non-obvious benefit: better attribution data. When bots trigger pageviews without referrers, they dilute your traffic source reports. After filtering, you’ll see clearer breakdowns of which channels actually send engaged visitors. That matters when you’re deciding where to spend time or ad budget.

    If you’re running a content site and using traffic numbers to pitch sponsors, filter first. Advertisers who audit your analytics will spot bot inflation immediately. Showing 6,000 real visitors is more credible than claiming 10,000 mixed visits.

    Want more operator-to-operator breakdowns like this? Subscribe to One Two Three Send for weekly deep dives into the tools and tactics that actually move the needle for solo operators and small teams.

  • Analytics event deduplication: when two tools count the same click twice

    Analytics event deduplication: when two tools count the same click twice

    Analytics event deduplication: when two tools count the same click twice
    Photo by 1981 Digital on Unsplash

    If you’re running Google Analytics 4 alongside a product analytics tool like Plausible, Fathom, or Mixpanel, there’s a good chance you’re counting the same user actions multiple times. Not because of a bug—because of how event tracking actually works when you layer tools.

    The problem isn’t visible in any single dashboard. It shows up when you try to reconcile conversion counts across platforms, or when your ad spend math stops making sense because your attribution model is inflated by 20–40%.

    Why duplicate events happen

    Most analytics tools fire events client-side, triggered by the same user interaction. When someone clicks a “Start Free Trial” button, here’s what fires:

    • Your Google Analytics 4 snippet sends a generate_lead event
    • Your product analytics tool sends a trial_started event
    • Your CRM webhook logs a signup event
    • Your email platform records a subscriber_added event

    Each tool counts it as a discrete conversion. If you’re summing these in a spreadsheet or a data warehouse, you’ve just turned one signup into four.

    The issue gets worse with retargeting pixels. Meta’s Pixel, TikTok’s Pixel, and Reddit’s Pixel all fire their own conversion events. If you’re optimizing ad campaigns based on those signals, you’re feeding the algorithm duplicate data—and it will bid as if you’re converting at 3× your actual rate.

    Server-side tracking doesn’t solve it automatically

    Sending events server-side through Google Tag Manager Server or Segment reduces client-side load and improves data accuracy, but it doesn’t deduplicate by default.

    Unless you explicitly configure deduplication logic—usually via event IDs or timestamps—your server will still forward the same conversion to multiple destinations. You’ve just moved the problem from the browser to your backend.

    Segment’s spec includes a messageId field that’s supposed to handle this, but downstream tools don’t always respect it. GA4 ignores it entirely unless you map it to a custom parameter and write your own deduplication rule in BigQuery.

    How to fix it without tearing down your stack

    Start by assigning a unique event ID at the point of capture—ideally a UUID generated client-side or server-side at the moment the event fires. Pass that ID to every analytics tool as a custom property.

    In GA4, add it as a custom parameter: event_id. In Mixpanel, use $insert_id. In Amplitude, it’s insert_id. Most tools have a native field for this; check the docs.

    Then, when you’re aggregating data in a warehouse or a BI tool, deduplicate on that ID. A simple SQL DISTINCT or ROW_NUMBER() OVER (PARTITION BY event_id) will collapse duplicates.

    If you’re using a customer data platform like Segment or RudderStack, configure deduplication rules in the destination settings. Segment lets you set a deduplication window (usually 24 hours) and a key (like messageId or a custom property). It won’t stop all duplicates, but it catches most.

    When to accept some duplication

    Not every duplicate is worth fixing. If you’re using GA4 for high-level traffic analysis and Mixpanel for product funnels, the overlap might not matter—you’re answering different questions.

    The duplication that kills you is in attribution and ad reporting. If Meta thinks you converted 300 times this month when you actually converted 150, your cost-per-acquisition is fiction. Fix that first.

    For internal dashboards where you’re just tracking trends, a 10–15% duplication rate is noise. Don’t spend a week engineering a perfect solution when the real issue is whether your content is converting at all.

    One more thing: if you’re running this site or something like it, reply and tell me which analytics stack you’re deduplicating right now. I’m curious what combinations are causing the most headaches in 2026.

  • Most analytics platforms count the wrong conversion timestamp

    Most analytics platforms count the wrong conversion timestamp

    Most analytics platforms count the wrong conversion timestamp
    Photo by Stephen Dawson on Unsplash

    Open any analytics dashboard and you’ll see conversion timestamps down to the second. Clean numbers. Precise attribution. The only problem: most platforms are measuring the wrong moment.

    Analytics tools record when the tracking pixel fired, when the webhook hit your server, or when the JavaScript event bubbled up. What they don’t capture—and can’t capture—is when the visitor actually decided to convert. That gap between decision and detection creates blind spots that skew how you read your funnel data.

    The detection lag problem

    A visitor reads your landing page at 2:14 PM. They’re convinced. But they don’t hit the button yet—they open three more tabs to compare pricing, check a review site, and read your refund policy. At 2:31 PM, they close the tabs and click through. Your analytics platform stamps the conversion at 2:31 PM and attributes it to a seventeen-minute session.

    The reality: the conversion happened in the first ninety seconds. Everything after that was confirmation bias and friction removal.

    This matters because most attribution models assign credit based on the timestamp of the tracked event, not the moment of intent. If you’re running time-based attribution windows—last-click within 7 days, for example—you’re giving credit to touchpoints that happened after the decision was already made.

    Google Analytics 4 defaults to a 30-day click window and a 1-day view window. Plausible and Fathom don’t track cross-session attribution at all. None of them distinguish between decision time and detection time, because the browser has no way to know when a visitor made up their mind.

    Where the gap shows up in your data

    Time-on-page averages get inflated. If your analytics say visitors spend an average of four minutes on your sales page before converting, you’re probably looking at two minutes of reading and two minutes of tab-switching and mental accounting. The page itself only held attention for half that window.

    Session duration becomes misleading for the same reason. A thirteen-minute session that ends in a sale might include eight minutes of the visitor doing something else entirely—answering an email, getting coffee, talking to a coworker. The conversion timestamp marks the end of that session, but the persuasive work was done much earlier.

    This shows up most clearly in email campaigns. You send a newsletter at 9:00 AM. A reader opens it at 9:14 AM, clicks through to your product page, and leaves the tab open while they finish their morning routine. At 10:02 AM, they come back to the tab and complete checkout. Your analytics platform records a 48-minute gap between click and conversion. Your email platform reports the click at 9:14 AM. Neither tool knows that the decision was made at 9:16 AM and everything else was logistics.

    How to interpret your timestamps correctly

    Start by cutting your reported time-on-page numbers in half as a mental heuristic. It’s not precise, but it’s closer to reality than taking the raw figure at face value. If your analytics say visitors spend six minutes on a landing page before converting, assume the actual engaged time was closer to three.

    For session-based conversion funnels, focus on the first touchpoint timestamp, not the last. If you’re trying to figure out what drives conversions, the moment someone entered your funnel is more predictive than the moment they finally clicked a button. This is especially true for content-driven businesses, where a visitor might read a blog post, leave, come back two days later, and subscribe. The blog post did the work; the subscription form just captured it.

    When you’re analyzing email campaign performance, measure click-to-conversion time but assume the decision window was much shorter. If your average click-to-purchase time is thirty minutes, the actual persuasion probably happened in the first five. The rest is tab management and distraction.

    For paid traffic, shrinking attribution windows make this worse. As platforms move toward same-day attribution—Meta and Google both tightened their windows in the past year—you lose visibility into conversions that were influenced early but detected late. A visitor who clicks your ad on Monday, thinks about it, and converts on Wednesday won’t show up in a one-day click window, even though the ad drove the decision.

    What you can do about it

    You can’t fix the detection lag, but you can design around it. If you’re running A/B tests on landing pages, extend your test duration to account for the gap between exposure and conversion. A visitor who sees variant B today might not convert until tomorrow, and if you stop the test too early, you’ll miss that delayed signal.

    For content attribution, track entry page separately from conversion page. If someone lands on a blog post and converts three sessions later, your analytics platform will credit the last session’s entry page—probably your homepage or a direct visit. Manually tagging your highest-intent content and tracking it as a first-touch dimension gives you a clearer picture of what actually moves people.

    If you’re using a tool like Google Analytics 4, create a custom event that fires when a visitor hits a high-intent action—scrolling to your pricing table, opening your FAQ accordion, clicking a comparison chart. Those micro-events are closer to the decision moment than the final conversion timestamp, and they give you a better signal for what’s working.

    For email-driven conversions, segment by time-to-click rather than time-to-conversion. If someone clicks your email link within five minutes of opening, that’s a strong signal regardless of when they complete checkout. Late conversions still count, but early clicks tell you more about your message’s persuasive power.

    One more thing: if you’re debugging a funnel that looks broken—high traffic, decent engagement, low conversions—check whether your analytics platform is recording conversions in a different session than the one where the decision happened. Cross-session attribution gaps are one of the most common reasons funnels appear to underperform when the real problem is measurement, not messaging.

    Want more breakdowns like this? Subscribe to One Two Three Send—we dig into the mechanics of online-business tools every week, with no fluff and no vendor spin.

  • Analytics UTM parameters break when platforms strip them mid-click

    Analytics UTM parameters break when platforms strip them mid-click

    You set up UTM parameters on every campaign link. You check your analytics dashboard. Half your traffic shows up as direct or referral with no campaign data attached. The parameters vanished somewhere between the user’s click and your server log.

    This isn’t a tagging mistake or a broken implementation. Social platforms, email clients, mobile apps, and third-party proxies strip, modify, or cache UTM parameters before they ever reach your site. The problem is structural, and it costs solo operators accurate attribution data every single day.

    Where UTM parameters disappear

    Instagram and TikTok in-app browsers cache the destination URL on first load, then serve that cached version on subsequent taps. If a user sees your post, taps the link, backs out, then taps again five minutes later, the second visit hits your site without UTM parameters because the app pulled the page from cache instead of following the full URL.

    LinkedIn’s link wrapper rewrites URLs when you post. A link with ?utm_source=linkedin&utm_medium=social&utm_campaign=launch gets routed through linkedin.com/safety/go, and sometimes the parameters don’t survive the redirect chain. The same happens on Facebook when the platform flags your domain for review or routes traffic through its link-shim service.

    Email clients strip query parameters they consider tracking identifiers. Apple Mail Privacy Protection prefetches links in the background, and iOS Mail strips parameters on some mailto and http links when the user has tracking protection enabled. Outlook’s Safe Links feature rewrites URLs and occasionally drops trailing parameters during rewrite.

    Link shorteners add another failure point. Bitly, TinyURL, and custom short-domain services sometimes cache the redirect destination. If you update the long URL with new UTM parameters after the short link is created, users who clicked the old short link may land on a cached version with stale or missing parameters.

    What actually survives

    UTM parameters work reliably on direct web traffic and on platforms that don’t proxy or rewrite links. Twitter/X still passes them through cleanly most of the time. Reddit does, too, unless the subreddit uses AutoModerator rules that strip query strings. Email platforms like MailerLite and Postmark preserve UTM parameters in plain-text and HTML emails as long as the link isn’t flagged by the receiving client’s anti-tracking filter.

    Search ads and display ads pass parameters without issue because the ad platform has no incentive to strip your tracking data—they want you to measure performance so you keep spending. Google Ads, Microsoft Ads, and Meta Ads all respect UTM conventions.

    Direct links posted in Slack, Discord, SMS, and WhatsApp usually work, though WhatsApp’s link preview service occasionally caches the destination and serves a parameter-free version on repeat taps.

    Workarounds that don’t scale

    Some operators try to append a cache-buster parameter like &cb=1234567890 to force platforms to treat each link as unique. This helps with caching issues but increases the risk that aggressive filters flag the URL as a tracking link and strip the entire query string. You trade one failure mode for another.

    Others embed campaign identifiers in the URL path instead of query parameters: example.com/launch-linkedin instead of example.com?utm_campaign=launch. This survives stripping but requires server-side rewrite rules and breaks when you run multiple campaigns to the same landing page. You end up creating dozens of duplicate URLs or writing complex routing logic.

    A third approach is to use first-party cookies or localStorage to persist campaign data after the first visit, then attribute conversions retroactively. This works only if the user converts on a return visit and only if your analytics tool supports cross-session attribution. Most don’t.

    What actually works

    Accept that UTM parameters will fail on 15–30% of clicks from social and email traffic. Plan your attribution model around that reality instead of trying to patch every leak.

    Use a dedicated link-management tool like Rebrandly or a self-hosted solution that logs the original UTM parameters server-side when the short link is created, then appends them to the destination URL at redirect time. This won’t fix client-side caching, but it ensures your tracking data is attached to the redirect, not just the short link.

    For high-value campaigns, create unique landing pages with campaign identifiers baked into the URL path. Reserve this for product launches, partnerships, and sponsored placements where you need accurate attribution and can afford the operational overhead.

    Track referrer headers alongside UTM parameters. When parameters are missing, your analytics tool can fall back to the HTTP referer header to identify the source platform. This won’t give you campaign-level detail, but it’s better than marking everything as direct traffic.

    Run a monthly audit of your top traffic sources in Google Analytics, Plausible, or Fathom. Filter for sessions with no UTM parameters and a known referrer domain. If you see significant traffic from l.instagram.com, lm.facebook.com, or t.co tagged as direct, you know where your parameters are breaking.

    Want to dig deeper into analytics setup and attribution models for solo operators? Reply with the tracking issue you’re trying to solve—we’ll cover it in a future issue.

  • Analytics event naming: when consistent schemas break multi-tool funnels

    Analytics event naming: when consistent schemas break multi-tool funnels

    Most solo operators inherit analytics event-naming advice from enterprise playbooks: pick a consistent schema, document it in a spreadsheet, enforce it across every tool. The promise is clarity—one event name, one definition, one source of truth.

    The reality is messier. When you track the same event across Google Analytics 4, a CRM, an email platform, and a payment processor, identical labels often mean subtly different things. GA4’s purchase event fires on confirmation-page load. Your payment processor’s purchase webhook fires when funds clear. Your CRM’s purchase tag triggers when a deal stage changes. None of them happen at the same moment, and none of them count the same subset of transactions.

    Forcing a single name across all four systems doesn’t unify your data—it hides the gaps.

    Where naming consistency helps

    Event schemas make sense within a single platform. If you’re routing custom events into GA4, a predictable structure—category_action_label or verb_noun—keeps your reports readable and your segments reusable. The same applies to customer-data platforms that ingest events from multiple sources but store them in one database.

    Consistency also helps when you’re debugging. If every button click follows the same pattern—click_cta_header, click_cta_sidebar—you can filter by prefix and catch tracking gaps faster.

    But once you cross tool boundaries, the schema starts working against you.

    The multi-tool attribution gap

    Here’s the common scenario: you run a content site with a paid membership tier. A reader lands via organic search, opens three articles, clicks a paywall CTA, enters their email on a lead-magnet landing page, receives a nurture sequence, clicks a checkout link in email four, and completes payment.

    GA4 sees the paywall click and the checkout page view. Your email platform (MailerLite, Postmark, ConvertKit) sees the email opens and link clicks. Your payment processor (Stripe, Lemon Squeezy) sees the transaction. If you name every conversion point conversion, your attribution report shows three separate conversions with no shared context.

    You can’t merge them retroactively because the timestamps don’t align—GA4 logs in the user’s timezone, your email platform logs in UTC, and Stripe logs when the webhook fires, which might be seconds or minutes after the charge.

    Naming every step conversion or purchase makes your dashboard look unified. But when you try to calculate cost-per-acquisition or attribute revenue to a specific traffic source, you’re double- or triple-counting.

    Namespace by tool, not by intent

    A better approach: prefix event names with the tool or surface that generated them. Instead of purchase everywhere, use:

    • ga4_purchase for client-side page tracking
    • stripe_charge_succeeded for payment webhooks
    • crm_deal_closed for CRM pipeline updates
    • email_checkout_click for link tracking in transactional sequences

    This naming convention makes the gaps explicit. When you run a report and see four different revenue events for the same order, you know immediately which one to trust (usually the payment processor) and which ones are proxies.

    It also makes it easier to build rollup metrics. If you want a single “conversion” event that fires once per paying customer, you write a rule: count stripe_charge_succeeded, ignore everything else. You’re not guessing which purchase event is the real one.

    When to break the namespace rule

    There’s one case where tool-agnostic naming still makes sense: when you’re using a customer-data platform like Segment, RudderStack, or Hightouch to route events from a single source to multiple destinations.

    In that setup, the CDP is the source of truth. You send one Order Completed event with a structured payload, and the CDP forwards it to GA4, your CRM, your email tool, and your data warehouse. Each destination interprets the same event in its own way, but you’re starting from a single canonical definition.

    Even then, you’ll want to add destination-specific properties—GA4 needs transaction_id, Stripe needs payment_intent, your CRM needs deal_id—but the top-level event name can stay consistent.

    What this means for your reporting stack

    If you’ve been wrestling with attribution models that don’t add up, check your event-naming layer first. Open your GA4 events list, your email platform’s link-tracking log, and your payment processor’s webhook history. Look for overlapping names. If you see the same label in three places, assume they’re counting different things until you prove otherwise.

    Then decide which tool owns the metric. Revenue attribution? That’s your payment processor. Email engagement? That’s your ESP. Page-level behaviour? That’s GA4. Name your events to reflect ownership, not aspiration.

    The goal isn’t a beautiful schema—it’s a reporting stack where every number has one clear source and every query returns the same answer twice.

    Got a question about analytics, attribution, or tooling for solo operators? Reply to this newsletter—we read every response and use the best ones for future deep-dives.

  • Google Analytics 4 event debugging: where custom events disappear

    Google Analytics 4 event debugging: where custom events disappear

    You fire a custom event in Google Analytics 4. You check DebugView. Nothing. You check the real-time report. Still nothing. Three days later, the event count sits at zero.

    Custom events in GA4 fail more often than platform defaults, and the diagnostic trail is deliberately obscure. If you run a content business that tracks signups, downloads, or affiliate clicks through GA4 events, silent failures cost you attribution data you can’t recover.

    Here’s where custom events break, how to trace the failure, and what to fix before you file a support ticket or hire a developer to rebuild your entire tracking stack.

    The four places custom events disappear

    1. The event never fires in the browser. Your tag manager condition is wrong, the trigger element doesn’t exist on the page, or JavaScript errors block execution. Open your browser’s console, filter by “gtag” or “dataLayer,” and watch for the push. If you see nothing when you click the button or load the page, the event isn’t leaving the client.

    2. The event fires but GA4 rejects it. Event names longer than 40 characters get dropped. Parameter names with spaces, hyphens, or uppercase letters get silently ignored. If your event is called affiliate_link_clicked_homepage_sidebar_cta, GA4 truncates it. If your parameter is link-URL, it’s gone. Check the naming rules and test with a simplified version.

    3. The event arrives but DebugView doesn’t show it. DebugView only displays events from sessions where debug mode is active—either through the GA4 DebugView Chrome extension, a debug_mode parameter in your gtag config, or a query string flag. If you’re testing in an incognito window without the extension, you won’t see anything even if the event is logging correctly in production. Switch to the real-time report or wait 24–48 hours for the event to appear in the standard reports.

    4. The event logs but doesn’t appear in reports. GA4 has a 500-event-name limit per property. If you’ve already registered 500 custom events (common in properties that auto-track every button click or scroll depth), new events get dropped. You won’t get a warning. Check your event list under Configure → Events and archive unused events to free up slots.

    What to check first

    Start with the browser console, not DebugView. Log in as a test user, trigger the event, and confirm the dataLayer.push fires. If it does, check the payload for naming violations—no spaces, no capitals, no special characters except underscores.

    Next, verify the event reaches Google. Open the Network tab in your browser’s developer tools, filter by “collect,” and look for a request to google-analytics.com/g/collect with your event name in the query string. If you see it there, the event left your site. If GA4 still doesn’t show it, the rejection happened server-side.

    Finally, check your property’s event quota. Go to Configure → Events and count how many are marked as custom. If you’re near 500, you’ve hit the ceiling. Archive old events or consolidate similar actions under a single event name with dynamic parameters.

    Common silent failures

    Measurement Protocol events submitted without a valid client_id get logged but attributed to no user. If you’re sending server-side events from a backend script, make sure you’re passing the same client_id that the client-side gtag generated. Mismatched IDs orphan the event.

    Events fired before the GA4 config tag loads get lost. If you’re triggering a custom event on page load and your tag manager fires it before the GA4 initialization completes, the event won’t attach to a session. Add a delay or fire the event only after gtag('config') resolves.

    Cross-domain tracking breaks event attribution if the _ga cookie doesn’t transfer. If you’re tracking affiliate clicks that redirect to an external domain and back, make sure your linker parameter is appended correctly. A missing or malformed linker drops the session context, and the returning event lands in a new session with no history.

    When to rebuild vs. patch

    If fewer than 10% of expected events are missing, patch the specific failure—usually a naming issue or a trigger condition. If more than half your custom events don’t log, your implementation is structurally broken. Start over with a fresh tag manager container, test each event in isolation, and document the client_id and session flow.

    GA4’s error messages are deliberately vague. The platform won’t tell you which parameter failed or why an event didn’t register. Build your own logging layer—either a server-side event collector that mirrors GA4 calls or a Google Sheets endpoint that receives a copy of every dataLayer push. When GA4 goes silent, your backup log will show what actually fired.

    Got a GA4 event that refuses to log? Reply with the event name and trigger setup—I’ll tell you where to look.

  • Plausible vs. Fathom vs. Simple Analytics: which privacy-first tool to pick

    Plausible vs. Fathom vs. Simple Analytics: which privacy-first tool to pick

    Privacy-first analytics platforms sell themselves on the same pitch: no cookies, no GDPR banners, fast scripts, and clean dashboards. Plausible, Fathom, and Simple Analytics dominate the category, but they differ in meaningful ways once you’re past the landing page.

    If you run a content-driven business and you’re tired of Google Analytics bloat—or you need to ditch cookie banners without losing visitor insight—here’s what each tool does well, where it falls short, and who should pick which.

    Pricing and visitor thresholds

    All three charge based on monthly pageviews, but the tiers and caps differ.

    Plausible starts at $9/month for up to 10,000 pageviews. You pay $19/month for 100,000 views, $29/month for 200,000, and pricing scales from there. If you exceed your plan, Plausible emails a warning and asks you to upgrade—it doesn’t cut off tracking.

    Fathom starts at $15/month for 100,000 pageviews. The entry tier is higher, which means if you’re sub-50,000 views per month, you’re overpaying compared to Plausible. Fathom counts by pageviews across all sites on your account, so multi-site operators hit limits faster.

    Simple Analytics starts at €19/month (roughly $20 USD) for 100,000 pageviews. Pricing is similar to Fathom but billed in euros. Simple Analytics offers a “business” tier that includes mini-websites—embedded public dashboards you can share without login—which the other two don’t bundle at the base level.

    If you’re under 50,000 pageviews per month, Plausible wins on cost. Above that threshold, all three converge, and the decision shifts to features and interface preference.

    Feature differences that matter

    All three tools show you top pages, referrers, devices, browsers, and countries. The gaps appear when you need goals, funnels, or custom dimensions.

    Plausible supports custom event goals at no extra cost. You can track button clicks, form submissions, or file downloads by adding a JavaScript snippet or using their API. Plausible also offers a custom properties feature that lets you attach metadata to events—useful if you want to track blog post category performance or product variant clicks. The dashboard is fast, and the filter UI is clean. Plausible is open-source and offers a self-hosted option if you want to run it on your own infrastructure.

    Fathom keeps the interface even simpler. Custom events exist, but Fathom doesn’t support event metadata or properties—you get event names and counts, nothing more granular. That’s fine if you’re tracking basic conversions (newsletter signups, link clicks), but limiting if you need segmentation. Fathom’s uptime monitoring feature sends you alerts if your site goes down, which is a nice bundled extra the others lack. Fathom is closed-source and cloud-only.

    Simple Analytics falls between the two. It supports events and metadata, similar to Plausible. Simple Analytics also has a built-in automated events feature that tracks outbound links and file downloads without manual setup. The dashboard lets you create multiple views and share them publicly via mini-websites, which is useful if you want to show traffic stats to sponsors or partners. Simple Analytics is open-source like Plausible, but its self-hosted version requires more technical setup.

    Script size and page speed impact

    All three advertise sub-1KB scripts. In practice, Plausible’s script is around 1KB, Fathom’s is 1.4KB, and Simple Analytics is 3KB. The difference is marginal—none will tank your Core Web Vitals—but if you’re optimizing aggressively, Plausible has the smallest footprint.

    All three scripts are proxy-friendly, meaning you can serve them from your own domain to avoid ad blockers. Plausible and Fathom document this clearly; Simple Analytics requires a bit more config work.

    Who should pick which

    Pick Plausible if you’re under 50,000 pageviews per month, you want custom event properties, or you value open-source software and self-hosting optionality. Plausible’s pricing scales cleanly as you grow, and the event tracking flexibility covers most operator needs without requiring a migration later.

    Pick Fathom if you want the simplest possible dashboard, you’re already above 100,000 pageviews, and you value the uptime monitoring extra. Fathom’s lack of event metadata keeps the interface uncluttered, which some operators prefer. It’s also the most polished UI of the three—if aesthetics matter to your daily workflow, Fathom feels the most refined.

    Pick Simple Analytics if you need public dashboard sharing (for sponsors, clients, or transparency pages), you want automated event tracking without manual setup, or you’re already comfortable with euro billing. Simple Analytics sits in the middle on features and pricing, which makes it a safe default if you’re unsure.

    One thing all three miss

    None of these tools track individual user journeys or session replays. If you need to see how a single visitor navigated your site—or you want heatmaps—you’ll need a separate tool or a hybrid setup. That’s by design: privacy-first analytics don’t fingerprint users. But it’s a tradeoff worth naming if you’re migrating from Google Analytics and expect session-level data.

    If you’re running a newsletter or content site and you just need clean traffic numbers without the compliance headache, any of these three will work. The decision comes down to pageview volume, whether you need event metadata, and how much you care about dashboard aesthetics.

    Want more tool breakdowns like this? Reply and tell us which category to compare next—we’ll prioritize reader requests.

  • Analytics tool sampling: when free plans skip your best traffic

    Analytics tool sampling: when free plans skip your best traffic

    Most analytics platforms don’t show you every visitor. On free and starter plans, tools like Google Analytics 4, Fathom, and Plausible apply data sampling once you cross certain thresholds—sometimes without telling you clearly in the dashboard.

    Sampling means the platform processes a subset of your traffic and extrapolates the rest. For solo operators running content sites or newsletters, this can distort the metrics you’re optimizing for: which posts drive signups, which UTM sources convert, and how long readers stay.

    Here’s what sampling looks like in practice, when it kicks in, and how to tell if your numbers are directionally wrong.

    What gets sampled and what doesn’t

    Sampling typically applies to custom reports, segments, and date-range queries—not the default real-time or overview dashboards. If you filter traffic by UTM campaign, landing page, or device type over a trailing 90-day window, you’re more likely to hit sampling.

    Google Analytics 4 samples when a query touches more than 10 million events in the selected property and date range. For a site logging 50,000 monthly sessions with typical event instrumentation (page views, scrolls, clicks), you’ll cross that threshold in about six months of retained data.

    Plausible and Fathom don’t sample on their paid plans, but their free tiers and trials cap total event volume. Plausible’s free plan allows 10,000 monthly page views before sampling or blocking; Fathom’s trial is capped at 30 days and 100,000 page views, after which data stops flowing entirely unless you convert.

    The metrics most affected: conversion funnels, cohort retention, and multi-touch attribution. Sampling drops edge-case paths—your highest-intent visitors often behave differently from the median, so a 10% sample may miss the behavior that matters most.

    How to spot sampling in your reports

    Google Analytics 4 shows a green checkmark or yellow warning icon at the top of exploration reports. The yellow icon means your query was sampled; the percentage shown (e.g., “based on 8.3% of sessions”) tells you how much data was used.

    If you’re running a custom segment—say, traffic from a specific referrer with a conversion event—and the icon shows sampling, your funnel metrics are modeled estimates, not raw counts.

    Plausible and Fathom don’t display sampling warnings because they don’t sample on paid plans. If you’re on a free or trial tier and your traffic exceeds the cap, you’ll see a hard cutoff: events stop logging, or the dashboard shows partial days.

    Other platforms—Mixpanel, Heap, Amplitude—offer generous free tiers but throttle or sample retroactively once you exceed event limits. Mixpanel’s free plan caps at 20 million monthly events; past that, older data gets archived and queries slow down or return incomplete results.

    When sampling breaks your decisions

    Sampling matters most when you’re optimizing for conversion rate, attribution, or cohort behavior. If you’re A/B testing two landing pages and your analytics tool samples the traffic, a 2% lift in conversions might be noise, not signal.

    Example: You’re tracking newsletter signups from three UTM sources—organic search, Twitter, and a paid Facebook campaign. GA4 samples your 90-day report at 12%. The dashboard shows Twitter driving 40 signups and Facebook driving 38. In reality, Facebook drove 52 and Twitter drove 29—but the sample skewed toward a few high-traffic Twitter days.

    You reallocate budget based on bad data. Two weeks later, your cost per signup doubles.

    Sampling also hides outlier sessions: your longest time-on-page visits, your highest scroll depths, and your multi-page readers. These are your most engaged users, and they’re statistically rare. A 10% sample has a lower chance of capturing them.

    How to avoid or reduce sampling

    The simplest fix: narrow your date range and segment size. Instead of querying 90 days of traffic with five filters, query 30 days with two. If GA4 still samples, break the report into weekly chunks and aggregate manually in a spreadsheet.

    If you’re on Google Analytics 4 and sampling is chronic, consider exporting raw event data to BigQuery. GA4’s BigQuery export is free for up to 1 million events per day on the free tier, and queries run on unsampled data. The learning curve is steep—you’ll need SQL and a basic understanding of GA4’s event schema—but it’s the only way to guarantee complete data at scale.

    For operators who don’t want to manage SQL, switching to a paid analytics plan eliminates sampling. Plausible starts at $9/month for 10,000 monthly page views with no sampling. Fathom starts at $14/month for 100,000 page views, also unsampled. Both platforms count page views, not events, so instrumentation is simpler.

    If you’re running a high-traffic site (500,000+ monthly page views), expect to pay $50–$100/month for unsampled analytics. That’s the floor for tools that process every session.

    One more thing: sampling isn’t always disclosed

    Not every platform tells you when data is modeled or incomplete. If your dashboard shows a suspiciously round conversion rate—exactly 5.0%, not 4.87%—or if your funnel drop-off percentages don’t add up to 100%, you’re probably looking at sampled or aggregated data.

    Test this by exporting a raw event log (if your tool supports it) and comparing totals to the dashboard. If the counts don’t match, ask support whether sampling is applied and at what threshold.

    For newsletter operators and solo founders, unsampled data isn’t perfectionism—it’s the difference between knowing which traffic source pays for itself and guessing based on a model that drops your best readers.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep-dives on the tools and tactics that run online businesses.

  • Analytics dashboards hide more than they reveal

    Analytics dashboards hide more than they reveal

    Open Google Analytics, Plausible, or Fathom right now. You’ll see pageviews, sessions, bounce rate, referrers. Clean charts. Tidy numbers. Everything you need to know about your traffic.

    Except you’re looking at a summary of a summary of a summary. The dashboard is a lossy compression algorithm designed to make patterns visible—and in doing so, it hides the outliers, the edge cases, and the signal buried in the noise.

    If you’re running a content business, those hidden details are where the decisions live.

    What the default view doesn’t show you

    Most analytics dashboards aggregate by default. They show you total sessions, average time on page, top landing pages. That’s fine for a monthly report, but it flattens the distribution.

    Here’s what vanishes:

    • Single-page sessions that converted. A reader lands on your pricing page, scrolls to the bottom, clicks “subscribe,” and leaves. Bounce rate: 100%. Value: high. The dashboard flags it as a failure.
    • Referrer context beyond the domain. You see “twitter.com” in your referrer log. You don’t see which tweet, which reply thread, or whether it came from a quote-tweet with 800 impressions or a reply buried three levels deep.
    • Time-on-page outliers. Your median time on page is 1:20. One reader spent 22 minutes. Another spent four seconds. The average says nothing about either.
    • Entry and exit paths that don’t follow your funnel. You assume readers land on your homepage, browse, then subscribe. Half of them land on a three-year-old post, read two paragraphs, and subscribe from the inline CTA. Your dashboard doesn’t highlight that path unless you go looking.

    Default dashboards are built for SaaS companies with linear funnels. Content businesses don’t have linear funnels. Readers enter from anywhere, stay as long as they want, and convert when something clicks. The dashboard doesn’t map that.

    The data you need to export manually

    If you want to see what’s actually happening, you need to pull raw session logs or build custom reports. Here’s what to look for:

    Session duration distribution, not average. Export time-on-site data and chart it as a histogram. You’ll see three clusters: under ten seconds (accidental clicks or bots), 30 seconds to two minutes (skimmers), and five minutes-plus (engaged readers). The third group is your real audience. The dashboard average blends all three into a number that describes no one.

    Conversion paths, not just conversion rate. Most analytics tools let you build a funnel report. Set it to show all paths, not just the primary one. You’ll find readers who convert after visiting your about page, your uses page, and a random blog post from 2023. That’s not a broken funnel—it’s how trust builds in a content business.

    Referrer URLs, not referrer domains. If you’re using GA4, enable the full referrer URL in your data stream settings. If you’re using Plausible or Fathom, export your referrer data and sort by frequency. You’ll see which specific tweets, Reddit threads, or Hacker News comments are sending traffic. That tells you what to do more of.

    Exit pages for engaged sessions only. Filter your exit-page report to sessions longer than two minutes. You’ll see where your best readers leave. If they’re exiting from your pricing page, your CTA might be unclear. If they’re exiting from a post with no CTA, you’re leaving conversions on the table.

    When to ignore the dashboard entirely

    Sometimes the dashboard is wrong in a way that matters.

    If you’re running a small operation—under 10,000 sessions a month—your sample size is too small for statistical patterns to emerge. A single Reddit post can double your traffic for a day and skew your monthly average. The dashboard will show a spike, then a drop, and suggest you’re losing momentum. You’re not. You just had one good day.

    If you’re publishing sporadically, your traffic will look like a sawtooth. The dashboard will show declining engagement because it assumes consistent output. It doesn’t know you took two weeks off.

    If you’re testing a new traffic channel—say, you’re experimenting with Pinterest or Threads—the dashboard will bury it under “other” until it hits 5% of total traffic. You won’t see early traction unless you filter for it.

    In all three cases, the dashboard is technically accurate. It’s just not useful.

    What to do instead

    Set up three custom reports and review them monthly:

    • A session-duration histogram, filtered to organic and referral traffic only.
    • A conversion-path report showing all routes to subscription, not just the top funnel.
    • A referrer-URL export, sorted by engaged sessions (two minutes or longer).

    These three views will tell you more about your audience than any pre-built dashboard. They take ten minutes to set up and five minutes to review. The insight-to-effort ratio is better than anything else in your analytics stack.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep dives on the tools and tactics that actually move the needle for solo operators.

  • Traffic attribution breaks when you run multiple campaigns at once

    Traffic attribution breaks when you run multiple campaigns at once

    Most analytics platforms promise to tell you exactly where your traffic came from. Google Analytics 4 shows you a tidy funnel with source, medium, and campaign labels. You see “organic search” or “Facebook / cpc” and assume you know what’s working.

    But if you’re running more than one acquisition channel at the same time—SEO content, a Google Ads campaign, and a LinkedIn presence, for example—your attribution data is almost certainly lying to you.

    The problem isn’t the tools. It’s that attribution models can’t handle the way real people behave online.

    Why multi-touch attribution falls apart

    Attribution models try to assign credit for a conversion across multiple touchpoints. GA4 offers data-driven attribution by default, which sounds sophisticated until you realize it’s still guessing.

    Here’s what actually happens: someone finds your site via organic search, reads a post, leaves. Three days later they see your LinkedIn post, click through, subscribe. Two weeks after that, they click a retargeting ad and buy your course.

    GA4 will credit the last non-direct click—the retargeting ad—even though the organic post did most of the work. If you switch to first-click attribution, you overweight SEO and ignore the fact that your ad closed the deal. Data-driven attribution tries to split the difference, but it’s still modeling behavior it can’t fully see.

    Cross-device journeys make it worse. If someone reads your newsletter on their phone and later converts on desktop, most analytics platforms treat those as two separate users unless you’re running a logged-in experience with user IDs.

    The result: you look at your attribution report and think Facebook is outperforming SEO, so you cut your content budget. Three months later, your paid campaigns stop converting because there’s no top-of-funnel content feeding them.

    What to track when attribution breaks

    Instead of trusting last-click or data-driven models, track channel performance in isolation and watch for correlation, not causation.

    Segment by landing page source. If most of your organic traffic lands on blog posts and most of your paid traffic lands on a dedicated landing page, you can compare conversion rates by entry point. It’s not perfect, but it’s more honest than pretending GA4 knows which click “caused” the sale.

    Use UTM parameters religiously, but don’t over-rely on them. Tag every link you control—social posts, email campaigns, guest articles. But remember that UTMs only tell you where the last click came from. If someone clicks your LinkedIn post, browses, leaves, and returns via direct traffic, the UTM is gone.

    Track assisted conversions separately. GA4’s “Advertising” workspace has an assisted conversions report that shows which channels appeared earlier in the funnel, even if they didn’t get last-click credit. It’s buried, but it’s one of the few reports that acknowledges multi-touch reality.

    Run channel blackout tests. This is the only way to measure true incrementality. Pause one channel completely for two weeks and watch what happens to your overall conversion volume. If you turn off paid ads and conversions drop by exactly the amount those ads were generating, they were working. If conversions stay flat, your paid traffic was cannibalizing organic visits that would have converted anyway.

    When to stop caring about attribution

    If you’re a solo operator pulling in less than $10K/month, attribution modeling is probably a distraction. You don’t have enough traffic or conversions to make statistical inferences, and you’re better off focusing on channel-level metrics: CPM for paid ads, click-through rate for email, time-on-page for SEO content.

    Attribution matters when you’re spending enough that a 10% efficiency gain is worth the analytical overhead. For most indie operators, that threshold is somewhere north of $5K/month in paid acquisition spend.

    Below that, track what you can measure cleanly—email open rates, organic impressions, ad spend per signup—and accept that the handoff between channels is a black box. Your job is to keep all the channels healthy, not to perfectly allocate credit between them.

    A better question than “which channel converted?”

    Instead of asking which channel gets credit for the sale, ask: which channels would cause revenue to drop if I turned them off?

    That’s a harder question to answer, but it’s the one that actually matters. It forces you to think in terms of systems, not funnels. Your SEO content feeds your email list. Your email list warms people up for your paid retargeting. Your retargeting closes deals that started with a Twitter thread six weeks ago.

    Attribution reports want to collapse that system into a single “winning” channel. In reality, the system only works when all the parts are running.

    If you want to get serious about measuring incrementality, set up holdout groups, run A/B tests at the channel level, and accept that you’ll never have perfect data. If you just want to grow your business, watch revenue per channel over time and invest more in whatever’s trending up—even if you can’t prove exactly why.

    Got a question about tracking, attribution, or analytics for your online business? Reply to this email—we read everything and answer the best questions in future issues.