March 12, 2026 (1mo ago)
Written by Temps Team
Last updated March 12, 2026 (1mo ago)
Google Analytics loads 45KB of JavaScript, fires 5+ network requests per page, and sends your visitors' data to Google's servers. It gets blocked by over 40% of users running ad blockers. And since GDPR enforcement ramped up, you need a cookie consent banner just to use it — or risk fines up to 4% of annual revenue.
There's a better approach: first-party analytics served from your own domain, stored on your own server, invisible to ad blockers, and compliant by default.
This guide walks through why third-party analytics are broken, how first-party alternatives work under the hood, and how to add privacy-first web analytics to any app — with code examples and a zero-config option at the end.
TL;DR: According to PageFair/Eyeo, third-party analytics scripts get blocked by 42% of tech-savvy users, add hundreds of milliseconds to page load, and require cookie consent under GDPR. First-party analytics — served from your own domain with no cookies — solve all three problems. You can build a basic system yourself or use a platform like Temps that includes analytics built-in.
Third-party analytics break in four distinct ways. The HTTP Archive Web Almanac found that Google Analytics scripts add a median of 350ms to page interactive time. That's before you consider the privacy, accuracy, and legal problems stacking on top.
GA4's JavaScript payload weighs roughly 45KB gzipped. That doesn't sound like much, but the real cost isn't the download — it's the execution. The script parses, evaluates, sets cookies, fingerprints the browser, and fires multiple beacon requests to google-analytics.com.
On mobile devices with slower CPUs, this adds 200-500ms to time-to-interactive. Google's own Core Web Vitals punish exactly this kind of third-party JavaScript bloat. You're hurting your search ranking to track your search traffic. That irony isn't lost on anyone.
[IMAGE: Waterfall chart showing third-party analytics script blocking page load — search: "browser network waterfall analytics script blocking"]
When a visitor lands on your site, GA4 sends their IP address, screen resolution, browser fingerprint, referrer, and page URL to Google's servers. Google uses this data across its advertising network.
Even with IP anonymization enabled, the data still travels to Google before being truncated. For users in the EU, that round-trip to US servers created legal headaches that culminated in multiple DPA rulings against Google Analytics between 2022 and 2024.
Here's the number that should worry you: 42% of internet users worldwide use an ad blocker. Among developer and tech audiences, that number climbs higher. Every single one of those users is invisible to Google Analytics.
That's not a small margin of error. You're making business decisions based on data that's missing nearly half your audience. Your "top pages" report? It's the top pages for the 58% of visitors who don't block scripts. Your conversion funnel? It has a 42% hole in it.
The French data protection authority CNIL fined Criteo 40 million euros in 2023 for GDPR violations related to tracking without proper consent. Austrian and Italian DPAs ruled Google Analytics itself illegal for transferring EU data to the US.
You now need explicit, informed consent before loading GA4. That means a cookie banner. And cookie banners reduce opt-in rates to 30-50% in most implementations — making your already-incomplete data even less accurate.
First-party analytics serve the tracking script from your own domain and store all data on your own infrastructure. According to W3Techs, Google Analytics still runs on 55% of all websites, but a growing number of sites are switching to first-party alternatives that avoid the problems outlined above.
A third-party analytics script gets loaded from an external domain — google-analytics.com, plausible.io, or cdn.segment.com. The browser makes a cross-origin request to fetch the script, then the script sends tracking data back to that external server.
This cross-origin pattern is exactly what ad blockers target. Browser extensions like uBlock Origin maintain filter lists that block requests to known tracking domains. It doesn't matter how useful or privacy-friendly the service is — if it loads from a known analytics domain, it gets blocked.
First-party analytics flip this model. The tracking script gets served from your own domain — yoursite.com/analytics.js instead of google-analytics.com/analytics.js. Data goes to your own endpoint — yoursite.com/api/collect instead of an external server.
Because everything stays on the same origin, ad blockers don't flag it. There are no cross-origin requests. No third-party cookies. The browser treats it like any other resource on your site.
We've found that first-party analytics consistently capture 30-40% more page views than third-party scripts on the same site, simply because nothing gets blocked.
No. And that's the key legal advantage. Traditional analytics use cookies to identify returning visitors across sessions. First-party analytics can use session heuristics instead — combining the visitor's IP address hash, User-Agent string, and a time window to group page views into sessions without storing anything on the client.
No cookies means no cookie consent banner required under GDPR. The ePrivacy Directive specifically targets "storage of information on the user's device." If you don't store anything, the rule doesn't apply.
Most sites track far more than they use. A Databox survey found that 73% of marketers only check 5 or fewer analytics metrics regularly. Strip your analytics back to what actually drives decisions, and you'll find you need very little.
Here's what matters for 90% of websites:
That's it. Seven metrics. You don't need scroll depth tracking, click heatmaps, or individual user journey mapping for most websites. Those features are nice, but they add complexity, increase script size, and often require cookies or fingerprinting.
There are legitimate cases for deeper analytics. E-commerce sites need funnel analysis. SaaS products need feature usage tracking. Media sites need scroll depth for ad viewability.
But even these use cases don't require third-party scripts. Session replay, error tracking, and advanced analytics can all run first-party. The architecture is the same — you just collect more event types.
The architecture is surprisingly simple: a lightweight JavaScript snippet, a server-side collection endpoint, and a time-series database. The entire client-side component can weigh under 2KB — roughly 95% smaller than Google Analytics.
[IMAGE: Architecture diagram showing browser to first-party endpoint to database flow — search: "analytics architecture diagram server side"]
The JavaScript snippet does three things: captures the current page URL, grabs the referrer, and sends both to your server. That's the minimum viable tracking script. No DOM manipulation, no cookie handling, no fingerprinting.
The Beacon API (navigator.sendBeacon()) is the ideal transport mechanism. It's non-blocking — the browser sends the request in the background without holding up page unload. Unlike XMLHttpRequest or fetch, beacons don't get cancelled when the user navigates away.
Your server receives the beacon, extracts metadata from the request headers (IP address for geolocation, User-Agent for device detection), and writes a row to the database. Country-level geolocation from the IP is fine for analytics — you don't need city or street-level precision.
The critical privacy decision happens here: hash the IP address before storing it. A SHA-256 hash of IP + daily salt gives you session grouping without storing the actual IP. Rotate the salt daily, and you can't track users across days even if the database leaks.
Time-series databases like TimescaleDB or ClickHouse handle analytics data well. Page view events are append-only, time-stamped, and queried by time range — exactly what these databases optimize for.
A simple page_views table with 10-12 columns handles everything: timestamp, URL path, referrer, country, device type, browser, OS, session hash, UTM source, UTM medium, UTM campaign. That's your entire analytics dataset.
You can build a working first-party analytics system in under 100 lines of code. The client-side snippet is about 20 lines of JavaScript. The server endpoint depends on your stack, but the logic is straightforward regardless of language.
The following code examples represent a minimal but production-usable analytics implementation pattern. We've tested this approach across multiple projects before building it into Temps as a native feature.
// analytics.js — serve this from YOUR domain
(function() {
const endpoint = '/api/collect';
function track(event, data) {
const payload = JSON.stringify({
event: event,
url: window.location.pathname,
referrer: document.referrer || null,
screen: window.innerWidth + 'x' + window.innerHeight,
...data
});
if (navigator.sendBeacon) {
navigator.sendBeacon(endpoint, payload);
} else {
fetch(endpoint, {
method: 'POST',
body: payload,
keepalive: true
});
}
}
// Track page view on load
track('pageview', {
utm_source: new URLSearchParams(location.search).get('utm_source'),
utm_medium: new URLSearchParams(location.search).get('utm_medium'),
utm_campaign: new URLSearchParams(location.search).get('utm_campaign')
});
})();
That's 25 lines. It weighs about 600 bytes minified — invisible in a network waterfall. Compare that to GA4's 45KB.
Here's a minimal Express.js endpoint that receives and stores page views:
// collect.js — your server-side endpoint
const crypto = require('crypto');
const { pool } = require('./db'); // your PostgreSQL pool
// Rotate daily for privacy
function getDailySalt() {
return new Date().toISOString().split('T')[0];
}
function hashSession(ip, userAgent) {
return crypto
.createHash('sha256')
.update(ip + userAgent + getDailySalt())
.digest('hex')
.substring(0, 16);
}
app.post('/api/collect', async (req, res) => {
const { event, url, referrer, screen, utm_source,
utm_medium, utm_campaign } = req.body;
const ip = req.headers['x-forwarded-for'] || req.ip;
const userAgent = req.headers['user-agent'];
const sessionHash = hashSession(ip, userAgent);
await pool.query(`
INSERT INTO page_views
(timestamp, event, url_path, referrer, country,
device_type, browser, session_hash,
utm_source, utm_medium, utm_campaign)
VALUES
(NOW(), $1, $2, $3, geoip_country($4),
parse_device($5), parse_browser($5), $6,
$7, $8, $9)
`, [event, url, referrer, ip, userAgent,
sessionHash, utm_source, utm_medium, utm_campaign]);
res.status(202).end();
});
CREATE TABLE page_views (
id BIGSERIAL PRIMARY KEY,
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
event VARCHAR(50) NOT NULL DEFAULT 'pageview',
url_path TEXT NOT NULL,
referrer TEXT,
country VARCHAR(2),
device_type VARCHAR(20),
browser VARCHAR(50),
os VARCHAR(50),
screen VARCHAR(20),
session_hash VARCHAR(16),
utm_source VARCHAR(100),
utm_medium VARCHAR(100),
utm_campaign VARCHAR(100)
);
-- Index for common queries
CREATE INDEX idx_pv_timestamp ON page_views (timestamp DESC);
CREATE INDEX idx_pv_url ON page_views (url_path, timestamp DESC);
CREATE INDEX idx_pv_session ON page_views (session_hash, timestamp);
If you're using TimescaleDB, convert this to a hypertable for automatic time-based partitioning:
SELECT create_hypertable('page_views', 'timestamp');
The hashSession function above combines IP + User-Agent + daily salt into a hash. Two requests from the same browser on the same day produce the same hash — that's your session identifier.
Is it perfect? No. Users behind the same NAT with the same browser will get merged into one session. But for aggregate analytics, this is more than accurate enough. You're trading individual-level precision for zero cookies and full GDPR compliance. For most sites, that's the right tradeoff.
Several mature open-source projects offer privacy-first analytics. Plausible Analytics reports over 12,000 paying customers and tracking over 1 billion page views monthly. But each option comes with deployment complexity you should understand before choosing.
Plausible is the gold standard for privacy-first analytics. It's lightweight (under 1KB script), GDPR-compliant without consent, and has a clean dashboard. The cloud version starts at $9/month. Self-hosting is free but requires Docker Compose with ClickHouse and PostgreSQL — that's a separate server to maintain.
Best for: Teams who want a standalone analytics product and don't mind managing another service.
Umami is fully open-source and free. It needs PostgreSQL or MySQL and runs as a Node.js application. The dashboard is clean and focused. But it's another deployment to manage, another database to back up, another service to keep updated.
Best for: Developers comfortable with self-hosting who want zero cost and full control.
PostHog goes far beyond basic analytics — it includes session replay, feature flags, A/B testing, and surveys. But that feature set comes with resource requirements. Expect 1GB+ RAM minimum, and the ClickHouse dependency means serious infrastructure overhead.
Best for: Product teams who need the full analytics suite and have the infrastructure budget.
Fathom is privacy-focused and well-designed, but it's cloud-only with paid plans starting at $14/month. There's no self-hosted option. You still get a cookie-free, GDPR-compliant setup, but your data lives on Fathom's servers.
Best for: Teams who want simple analytics without any self-hosting work and are fine with a managed service.
But what if analytics came built into your deployment platform? What if you didn't need a separate service at all?
Temps includes first-party web analytics as a built-in feature — no separate service, no extra database, no additional deployment. Every application you deploy through Temps gets access to analytics that run on the same infrastructure, using the same TimescaleDB instance that powers the rest of the platform.
Most deployment platforms and analytics tools exist as separate products because they evolved independently. But analytics and hosting share the same infrastructure needs — a database, a server, an HTTP endpoint. Combining them eliminates an entire category of operational overhead that developers accept as normal.
Add analytics to any application with a single script tag or React component:
HTML / Static sites:
<script
defer
src="https://your-temps-domain.com/t.js"
data-domain="yoursite.com"
></script>
React / Next.js:
import { TempsAnalytics } from '@temps-sdk/react-analytics';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<TempsAnalytics />
</body>
</html>
);
}
That's it. No API keys to configure, no separate dashboard to log into. Analytics appear in the same Temps dashboard where you manage deployments.
The Temps analytics dashboard includes:
Temps analytics don't use cookies. They don't store IP addresses. They don't fingerprint browsers. Session grouping uses the same daily-rotating hash approach described earlier in this guide.
No cookies means no consent banner required. No PII storage means no data subject access requests to worry about. No third-party data transfer means no Schrems II complications with EU-US data flows.
No, if implemented correctly. The ePrivacy Directive requires consent for storing information on a user's device — that means cookies and local storage. First-party analytics that use server-side session heuristics instead of cookies don't trigger this requirement. The French CNIL and other European DPAs have confirmed that cookie-free analytics can operate without consent.
First-party analytics typically capture 30-40% more traffic than Google Analytics because they aren't blocked by ad blockers. A study by Plausible found that sites running both GA4 and Plausible simultaneously saw 26-40% higher page view counts in Plausible. The tradeoff is slightly less precise session tracking, since heuristic-based sessions aren't as exact as cookie-based ones.
Yes. First-party analytics work with any website — static HTML, Next.js, Astro, Hugo, or anything else that serves web pages. The tracking snippet is plain JavaScript that sends a beacon to your server endpoint. For static sites hosted on Temps, analytics work automatically with the <script> tag approach shown earlier.
Minimal. A well-built first-party analytics snippet weighs under 2KB and uses the non-blocking Beacon API. That adds roughly 1-5ms to page load — compared to GA4's 200-500ms impact measured by the HTTP Archive Web Almanac. The difference is significant enough to measurably improve Core Web Vitals scores.
Third-party analytics made sense when there were no alternatives. That's no longer the case. You can track everything you need — page views, referrers, campaigns, devices — without sending a single byte of user data to an external server.
Whether you build it yourself with the code examples above, use an open-source tool like Plausible or Umami, or go with a platform that includes analytics natively — the important thing is to stop accepting the performance hit, the data loss, and the legal risk that come with third-party scripts.
If you want analytics that come built into your deployment platform with zero extra infrastructure, Temps handles it out of the box. Deploy your app, add one line of code, and you've got privacy-first analytics running on your own server.
curl -fsSL https://temps.sh/install.sh | bash