Server-Side vs Client-Side Tracking for Indie Devs
Client-side scripts see rich behavior but get blocked; server-side tracking sees every request but less context. Accuracy, ad blockers and privacy, compared.
Client-side tracking runs a script in the visitor's browser; server-side tracking records events from your server, CDN or backend. Client-side gives you the richest picture of behavior (scrolling, clicks, single-page navigation, Web Vitals) but misses visitors who block scripts, roughly three in ten internet users by survey data and often more among developer audiences. Server-side sees every request and can't be blocked, but it sees less context and counts bots unless you filter them. For most indie developers the right answer is both: client-side for page behavior, server-side for the events that matter most (signups, payments) and for AI crawlers.
Key takeaways
- Around 29.5% of internet users worldwide used an ad blocker in 2025 according to GWI data compiled by DataReportal, and blockers usually stop analytics scripts too.
- Server-side tracking can't be blocked by browser extensions, but it can't see in-page behavior and must filter bots itself.
- Send conversions (signups, payments) from your server: they are too important to lose to a blocker, and payment webhooks are server-side by nature.
- Serving the analytics script from your own domain reduces blocking, but you must forward the real client IP or geolocation and bot detection break.
- Server-side is not automatically more private: GDPR applies to IP addresses wherever you process them.
What is the difference between client-side and server-side tracking?
| Client-side (JS tag) | Server-side (logs, middleware, backend events) | |
|---|---|---|
| Where it runs | Visitor's browser | Your server, edge function or CDN |
| Blocked by ad blockers | Often | No |
| Sees bots and AI crawlers | Only bots that run JavaScript | All of them (needs filtering) |
| Single-page app route changes | Yes, via the History API | Only full page loads and API calls |
| Scroll, clicks, engagement time | Yes | No |
| Screen size, time zone, Web Vitals | Yes | No |
| Referrer and UTM tags | Yes | Yes, from the request |
| Payments and backend events | Only if a page loads afterwards | Yes, from webhooks and jobs |
| Cached pages served by a CDN | Counted | Missed unless tracked at the CDN |
| Setup effort | One script tag | Code in middleware or backend, or log processing |
The two approaches fail in opposite places, which is why combining them works. The script misses people with blockers; the server misses what happens inside the page. Where they overlap (pageviews, referrers, UTM tags) you can compare them to measure how much each misses.
How much traffic do ad blockers hide from client-side analytics?
Survey data from GWI, published by DataReportal, put ad blocker use at about 29.5% of internet users worldwide in 2025 and somewhat higher in the US, with desktop well above mobile. Not every blocker blocks every analytics tool: uBlock Origin with the EasyPrivacy list, Brave's built-in Shields, and Firefox's strict tracking protection all target well-known analytics domains, while smaller tools and first-party setups slip through more often. Audience matters more than averages: a developer tool or a privacy-focused product can lose a much larger share than a recipe site.
Blocking is not the only client-side loss. Safari's Intelligent Tracking Prevention caps cookies set from JavaScript at seven days, so a client-side visitor ID on Safari stops recognizing returning visitors after a week. Visitors who close the tab before a deferred script loads are never counted. These effects are smaller than blocking, but they compound.
How do you measure your own block rate?
- 1.Pick a page that is not cached at the CDN, or count at the CDN itself, so every human pageview produces a server request.
- 2.Count server-side requests for that page over a week, filtering to HTML requests (Accept: text/html) from real browsers: exclude known bots, prefetches (Sec-Purpose: prefetch) and your own uptime checks.
- 3.Count client-side pageviews for the same page and window in your analytics tool, with bot filtering on.
- 4.The gap, as a share of the server count, is your approximate loss: (server − client) / server.
- 5.Repeat for a docs page and a marketing page. The block rate usually differs by audience, so one number for the whole site can mislead.
Expect some noise. Server counts include bots that look like browsers and that your filter misses, and client counts include SPA navigations the server never saw. The aim is an order of magnitude: 5% loss and 40% loss call for different decisions.
What does server-side tracking look like for an indie developer?
“Server-side tracking” covers three different things that are often confused:
- Request logging. Your web server, middleware or CDN records each request (path, referrer, user agent). It is the most complete count of requests and the only way to see AI crawlers, which never run JavaScript. See how to track AI crawlers.
- Backend events. Your application sends an event when something meaningful happens on the server: an account is created, a Stripe webhook confirms a payment, a trial converts. These are the events you can least afford to lose.
- Server-side tagging. A client-side tag sends data to your own server endpoint (for example server-side Google Tag Manager), which forwards it to vendors. Collection is still client-side; what moves to the server is the routing and filtering.
For an indie developer, the first two are where the value is. A backend event is a single HTTP call:
// After your database confirms the new account (server code)
await fetch("https://visitrack.app/api/track", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VISITRACK_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: "event",
visitorId: user.analyticsVisitorId ?? user.id, // ties it to earlier visits
name: "signup",
props: { plan: "free", method: "google" },
}),
});The example uses VisitTrack's server events endpoint; most analytics tools have an equivalent (GA4 calls it the Measurement Protocol). The detail that matters in any tool is the visitor ID: pass the same ID the browser script used, captured before signup or checkout, so the server event joins the visitor's earlier pageviews and inherits their source. Without it, you know a signup happened but not where it came from.
Should you proxy your analytics script through your own domain?
Serving the script and its collection endpoint from your own domain (say /stats/script.js and /stats/event, rewritten to the vendor) avoids blocklists that match on the vendor's domain. Many tools document a proxy setup, and frameworks make it a few lines: rewrites in Next.js, a Worker on Cloudflare, a location block in Nginx. Before you do it, know the trade-offs:
- The vendor now sees your proxy's IP instead of the visitor's. Unless the proxy forwards the client IP (X-Forwarded-For) and the vendor trusts it, every visitor appears to come from your hosting provider's data center: country data is wrong, and bot filters that flag cloud IPs may discard real people.
- Blockers adapt. Lists also match on script names and request patterns, so a proxy reduces blocking rather than eliminating it.
- It is a judgment call about consent. Someone running a blocker has expressed a preference. A cookieless, aggregate tool that stores nothing on the device is a much easier case to defend than routing an advertising tracker around a blocker.
- Use only what your vendor supports. A homemade proxy that the vendor's documentation doesn't describe can break attribution in ways that take weeks to notice.
Is server-side tracking more private?
Not inherently. It moves where processing happens; it doesn't change what you collect. The IP address is personal data under GDPR whether a browser script sends it or your server reads it from the request. Server-side setups can even be less transparent, because the visitor can no longer see in DevTools what is being sent where. What makes analytics privacy-friendly is the data model: no persistent cross-site identifiers, short-lived or hashed visitor IDs, no raw IP storage, aggregate reporting. Our cookieless tracking explainer covers that model, and the legal side is in Do you need a cookie banner for analytics?.
Server-side and the cookie rule
Moving collection to the server doesn't automatically take you out of the ePrivacy consent rule. If your server reads an identifier the browser stores (a cookie sent with each request, for example), that is still access to information on the device. The rule follows the identifier, not the location of the code.
Which setup should an indie developer choose?
| Your project | Client-side | Server-side | Why |
|---|---|---|---|
| Static site or blog | Script tag | CDN or edge function for crawlers (optional) | Nothing to convert server-side; crawlers are the main blind spot |
| Next.js or other SSR app | Script in the root layout | Proxy/middleware for crawlers; backend events for signups | Middleware already sees every request |
| SaaS with Stripe or another billing provider | Script for behavior | Signup event plus payment webhooks | Revenue must not depend on a script surviving |
| API or developer tool with a docs site | Script on docs | Request logs or middleware on docs; backend events for key creation | Developer audiences block scripts more |
| Browser extension or desktop app | Not applicable | Backend events only | No web pages to tag |
If you are on Next.js, the Next.js analytics guide walks through both halves, and the Next.js integration page has the minimal setup. For the business case of attributing revenue to traffic sources, which is where server-side events pay for themselves, see revenue attribution.
What does a combined setup look like?
A practical hybrid for a small SaaS fits on one page: the analytics script in your layout for pageviews, sources and engagement; a few lines of middleware forwarding user agents and paths so AI crawlers are visible; a server-side signup event sent after the account is created, carrying the browser's visitor ID; and your billing provider's webhook connected to analytics so each payment is attributed to the visitor's first touch. VisitTrack supports each of those pieces (script, crawler endpoint, server events, payment webhooks for Stripe, Polar, Lemon Squeezy, Paddle and Razorpay), but the architecture is the point, and it works with any tool that accepts server-side events.
The pattern holds up because each event is captured where it is most reliable: behavior in the browser, crawlers at the edge, conversions on the server. A blocked script then costs you some pageviews, not your signup or revenue numbers.
Is server-side tracking more accurate than client-side?
For counting requests and conversions, yes, because browser extensions can't block it. For in-page behavior such as scrolling, clicks and single-page navigation, no, because the server never sees it. Most accurate setups combine both.
Do ad blockers block server-side tracking?
No. Browser ad blockers can only stop requests the browser makes. Events your server sends, such as a signup recorded after account creation or a payment webhook, are invisible to them.
What percentage of visitors use ad blockers?
About 29.5% of internet users worldwide in 2025, according to GWI survey data compiled by DataReportal, with higher rates on desktop and among technical audiences. Your actual analytics loss depends on which tool you use and who your visitors are.
Does server-side tracking need cookie consent?
Not by itself, but it doesn't remove the requirement either. If your server reads an identifier stored in the browser, such as a cookie, the EU consent rule still applies. GDPR applies to IP addresses however you collect them.
Should I proxy my analytics through my own domain?
It reduces blocking, and many tools support it. Make sure your proxy forwards the real client IP and that the setup is documented by your vendor, otherwise geolocation and bot detection break.
What should I track server-side first?
Signups and payments. They are the events your business decisions depend on, they happen on your server anyway, and losing them to a blocked script distorts every conversion and revenue number downstream.