# Web Analytics Without Third-Party Scripts (2026)

> Add web analytics without third-party scripts: serve tracking from your own domain so fewer blockers hide your traffic. DIY, Umami and Temps compared.

David Viejo · Published 2026-03-12 · Updated 2026-10-20 · 12 min read

Canonical: https://temps.sh/blog/how-to-add-web-analytics-without-third-party-scripts

To add web analytics without third-party scripts, serve the tracking code from your own domain and send events to your own server. Build it in about 100 lines, self-host Umami or Plausible Community Edition, or use Temps, whose React SDK posts to /api/_temps on your own site.

## Can I Add Web Analytics Without a Third-Party Script?

Yes. You can add web analytics to any website without loading a script from an external domain or sending data to one. The approach is called first-party analytics: the tracking code is served from your own domain (or bundled into your app), events are sent to your own server, and nothing touches `google-analytics.com`, `plausible.io` or any other external host.

This matters for three reasons. Many ad blockers and privacy browsers block requests to known analytics hosts, so third-party analytics undercount, especially on technical audiences; serving from your own domain avoids most of those blocks. Third-party analytics send your visitors' data to another company, which raises international-transfer questions in the EU. And third-party trackers can follow visitors across sites, which first-party analytics on your own domain do not.

This guide covers how first-party analytics work under the hood, how to build a minimal system yourself, and how Temps includes analytics as a built-in platform feature, with no separate service or subscription.

> **TL;DR:** Third-party analytics scripts are often blocked, add JavaScript you don't control, and send visitor data to an external company. First-party analytics, served from your own domain and stored on your own server, address all three. You can build it yourself in about 100 lines, self-host a standalone tool such as Umami or Plausible Community Edition, or use Temps, which builds first-party analytics into the platform that deploys your app: the React SDK sends tracking to your own domain via `basePath="/api/_temps"`, so there is no separate analytics service to run.

---

## Why Are Third-Party Analytics Scripts a Problem?

Third-party analytics break in four distinct ways: performance, data control, accuracy and legal exposure.

### Performance Costs You Don't See

A third-party analytics tag is JavaScript you don't control, loaded from another origin. The download is only part of the cost: the script has to be parsed and executed, sets cookies and fires its own network requests. On slower mobile CPUs that work competes with your own code for the main thread, and Core Web Vitals measure the result.

### Your Users' Data Leaves Your Control

When a visitor lands on your site, GA4 sends their IP address, browser details, screen size, referrer and page URL to Google's servers. Even with Google's IP handling, the request itself still reaches Google before anything is truncated. Data protection authorities in Austria, France and Italy ruled against particular Google Analytics deployments in 2022 over exactly these transfers to the US.

### Ad Blockers Hide Part of Your Audience

Common filter lists block Google Analytics and other well-known analytics hosts by name. Every visitor whose blocker drops the request is invisible to your dashboard, and on developer-focused sites that can be a large share of traffic. You end up making decisions on data with a systematic gap.

### GDPR Turned Analytics into a Compliance Task

In the EU, setting non-essential cookies, including analytics cookies, generally requires prior consent under the ePrivacy rules, and sending data to a third-party processor adds GDPR obligations on top. That means a consent banner, and visitors who decline drop out of your data, making already-incomplete numbers less complete.

---

## Temps vs. Plausible vs. Umami: First-Party Analytics Compared

| Feature                           | Temps                                                                                 | Plausible                                                          | Umami                                                              |
| --------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------ |
| Tracking on your own domain       | Yes. The React SDK posts to `/api/_temps` on your site, which the Temps proxy handles | Cloud needs a proxy setup; self-hosted runs on a domain you choose | Self-hosted runs on a domain you choose; same-origin needs a proxy |
| Third-party cookies               | None. Two first-party cookies set by your own domain                                  | None (cookie-free)                                                 | None (cookie-free)                                                 |
| Consent in the EU                 | Generally needed for its two first-party cookies                                      | Commonly run without a banner                                      | Commonly run without a banner                                      |
| Self-hostable                     | Yes. Free, MIT / Apache 2.0                                                           | Yes (Community Edition; ClickHouse + PostgreSQL)                   | Yes (Node.js + PostgreSQL)                                         |
| Session replay built-in           | Yes (opt-in, `enableSessionRecording={true}`)                                         | No                                                                 | Yes (v3.1+)                                                        |
| Error tracking built-in           | Yes                                                                                   | No                                                                 | No                                                                 |
| Uptime monitoring built-in        | Yes                                                                                   | No                                                                 | No                                                                 |
| Included in a deployment platform | Yes: analytics, hosting, databases and email in one install                           | No, standalone service                                             | No, standalone service                                             |
| Pricing                           | Free to self-host; Temps Cloud coming soon from $29/mo                                | Cloud from $9/mo (10k pageviews); Community Edition free           | Free to self-host; Umami Cloud paid                                |

on each vendor's pricing page

The key structural difference: Plausible and Umami are standalone analytics tools you deploy alongside your app. Temps is a deployment platform that includes analytics natively, so analytics already run on the same server as your application. For a head-to-head, see [Temps vs Plausible](https://temps.sh/compare/vs-plausible).

---

## What Temps Analytics Does Differently

**Tracking goes to your own domain.** The React SDK's `basePath="/api/_temps"` prop sends every tracking request to your own site, where the Temps proxy handles it, and the SDK is bundled into your app rather than loaded from an analytics host. Blockers that match known analytics hostnames see only requests to your own origin, although a rule that targets the `/api/_temps` path could still block them.

**First-party cookies, data on your own server.** Temps identifies visitors with two first-party, HttpOnly cookies set by the Temps proxy on your domain: `_temps_visitor_id` (365 days) and `_temps_sid` (30 minutes). Visitor data stays in your own database and is not sent to a third-party analytics company, so there is no international transfer to an analytics vendor. The cookies are not cookie-free analytics, though: the [data ownership and privacy docs](https://temps.sh/docs/data-ownership-and-privacy) note that they generally need consent in the EU.

**Included in self-hosted Temps at no extra cost.** Temps is free to self-host under MIT / Apache 2.0, and that covers the deployment platform, web analytics, session replay, error tracking, uptime monitoring, managed databases and transactional email in one install. There is no separate analytics tier, no per-seat fee and no bandwidth bill. Temps Cloud, a hosted control plane for your own servers, is coming soon from $29/month.

---

## How Does First-Party Analytics Work?

First-party analytics flip the third-party model. Instead of loading a script from `google-analytics.com`, you serve it from `yoursite.com/t.js` or bundle it into your app. Instead of beaconing data to an external server, requests go to `yoursite.com/api/collect`.

Because everything stays on the same origin, there are no cross-origin requests and no third-party cookies, and blockers that work by hostname have nothing to match. Filter lists that target common script names or paths can still catch some setups, so a neutral path helps.

### Do You Still Need Cookies?

It depends on the implementation. Some analytics tools (Plausible, Umami) use no cookies at all. They group page views into sessions with server-side heuristics instead, such as a hash of the visitor's IP address and User-Agent with a salt that rotates daily.

Temps uses two first-party cookies (`_temps_visitor_id`, `_temps_sid`) set by your own domain to recognise returning visitors and stitch sessions. They are first-party cookies, not cross-site tracking cookies, and the data never leaves your server, but in the EU they generally still need consent. If you need a fully cookie-free setup, the DIY approach below, Plausible or Umami do that.

---

## How to Build a Minimal First-Party Analytics System

You can build a working first-party analytics system in under 100 lines of code. The client-side snippet is about 25 lines of JavaScript. The server endpoint depends on your stack, but the logic is the same in any language.

### The JavaScript Snippet

```javascript
// analytics.js — serve this from YOUR domain, not an external CDN
(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('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, well under a kilobyte minified, and it doesn't block rendering because `sendBeacon` runs in the background.

### The Server Endpoint

```javascript
// collect.js — your server-side endpoint
const crypto = require('crypto');
const { pool } = require('./db'); // your PostgreSQL pool

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();
});
```

### The Database Schema

```sql
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)
);

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:

```sql
SELECT create_hypertable('page_views', 'timestamp');
```

### Session Heuristics Without Cookies

The `hashSession` function above combines IP + User-Agent + a daily salt into a hash. Two requests from the same browser on the same day produce the same hash, and that is your session identifier.

Users behind the same NAT with the same browser will be merged into one session. For aggregate analytics, that is accurate enough. You trade individual-level precision for no cookies, which in many EU countries means you can skip the consent banner for this measurement. You are still processing IP addresses, so GDPR's other rules (a lawful basis, retention limits, transparency) still apply.

---

## Which Self-Hosted Tools Serve Analytics First-Party?

Any analytics tool you host on your own domain is first-party. The common choices are:

- **Plausible Community Edition:** the privacy-first standard, cookie-free, self-hosted with Docker Compose (ClickHouse and PostgreSQL).
- **Umami:** free and MIT-licensed, cookie-free, runs on Node.js with PostgreSQL.
- **PostHog:** product analytics with replay and feature flags; self-hosting is a Docker Compose "hobby" install that PostHog recommends only for low volumes (4 vCPU / 16 GB RAM recommended, per its [self-host docs](https://posthog.com/docs/self-host), October 2026). See [Temps vs PostHog](https://temps.sh/compare/vs-posthog).
- **Temps:** analytics built into the platform that deploys your app, alongside session replay, error tracking and uptime monitoring.

Each of the first three is a separate service you run, patch and back up next to your app; Temps is the one where analytics come with the hosting. For the full comparison, including GoatCounter, Ackee, Rybbit and Matomo, see our list of [Plausible alternatives](https://temps.sh/blog/7-best-plausible-alternatives-web-analytics-2026).

---

## How Temps Handles Analytics Without Third-Party Scripts

Temps includes first-party web analytics as a built-in platform feature: no separate service, no extra database and no additional deployment. Every app you deploy through Temps can send analytics to the same install, stored in the same TimescaleDB database that powers the rest of the platform. The [Temps analytics page](https://temps.sh/analytics) gives the overview, and the [analytics docs](https://temps.sh/docs/analytics) cover setup.

Analytics and hosting need the same things: a database, a server and an HTTP endpoint. Combining them removes a whole category of operational overhead.

### Setup for React / Next.js

```tsx
// app/layout.tsx
import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <TempsAnalyticsProvider
          basePath="/api/_temps"
          enableSessionRecording={true}
        >
          {children}
        </TempsAnalyticsProvider>
      </body>
    </html>
  );
}
```

`basePath="/api/_temps"` sends all tracking requests to your own site, and the SDK is bundled with your app, so the browser never contacts an external analytics domain. `enableSessionRecording={true}` turns on session replay (it is off by default), which records the DOM and user input, with inputs masked, and stores recordings on your own infrastructure. Leave it out if you only want analytics.

### Tracking Custom Events

Custom events are what funnels are built from; [building conversion funnels without Google Analytics](https://temps.sh/blog/how-to-build-conversion-funnels-without-google-analytics) shows the event schema and step-conversion queries.

```tsx
import { useTrackEvent } from '@temps-sdk/react-analytics';

export function SignupButton() {
  const trackEvent = useTrackEvent();

  return (
    <button
      onClick={async () => {
        await trackEvent('signup_clicked', { plan: 'free' });
      }}
    >
      Get started
    </button>
  );
}
```

### Accessing Analytics in Components

```tsx
import { useEffect } from 'react';
import { useTempsAnalytics } from '@temps-sdk/react-analytics';

export function TrackOnMount({ pageName }: { pageName: string }) {
  const { trackEvent } = useTempsAnalytics();

  useEffect(() => {
    trackEvent('page_viewed', { name: pageName });
  }, [pageName]);

  return null;
}
```

### For Static / HTML Sites

The [analytics docs](https://temps.sh/docs/analytics#setup) show the browser script loaded from unpkg:

```html
<script
  defer
  src="https://unpkg.com/@temps-sdk/analytics-browser@0.0.8/dist/temps.min.js"
></script>
```

Events go to your site's relative `/api/_temps` endpoints, which the Temps proxy handles for apps it serves. To avoid loading even the script from a third-party CDN, download `temps.min.js` and serve it from your own domain. Analytics then appear in the same Temps dashboard where you manage deployments.

### What You Get Out of the Box

The Temps analytics dashboard includes:

- **Real-time visitors:** live visitor count and currently active pages
- **Page views and top pages:** time-series charts and a breakdown by path
- **Referrers and campaigns:** traffic sources with UTM parameter parsing
- **Device and browser stats:** browser, OS and device type
- **Geographic data:** country, region and city from MaxMind GeoIP
- **Bot filtering:** known crawlers are flagged automatically, and AI crawler traffic gets its own view (see [how to track AI crawler traffic](https://temps.sh/blog/how-to-track-ai-crawler-traffic))
- **Session replay, error tracking and uptime monitoring** in the same dashboard

### Why It's Privacy-Friendly

Temps analytics use first-party cookies set by your own domain, not third-party tracking cookies set by an external analytics company. Visitor data, including the IP address the proxy records for geolocation and bot detection, stays on your server and is never sent to a third-party analytics vendor. There is no built-in IP anonymisation setting, so cover IP storage in your privacy notice.

With no transfer to an analytics vendor, the EU-US transfer problem that made Google Analytics contested in Austria, France and Italy doesn't arise. Because you own the infrastructure, you set retention, handle deletion requests and minimise data on your own terms. Consent for the two cookies is still your responsibility; see the [data ownership and privacy docs](https://temps.sh/docs/data-ownership-and-privacy).

---

## Frequently Asked Questions

### How do I add web analytics without third-party scripts?

Serve the tracking code from your own domain and send events to your own server. You can write a small snippet and endpoint yourself (about 100 lines, shown above), self-host a tool such as Umami or Plausible Community Edition on your domain, or use Temps, where `<TempsAnalyticsProvider>` in a React app sends events to `/api/_temps` on your own site and stores them in your Temps database. For plain HTML sites, serve the Temps browser script from your own domain rather than the CDN.

### Do first-party analytics need a cookie consent banner?

It depends on whether they store anything on the visitor's device. Cookie-free first-party analytics (the DIY heuristic approach, Plausible, Umami) are commonly run without a consent banner, because the ePrivacy consent rule targets storing or reading information on the device; confirm this for your jurisdiction. Temps sets two first-party cookies (`_temps_visitor_id` and `_temps_sid`), and its [privacy docs](https://temps.sh/docs/data-ownership-and-privacy) say these generally need consent in the EU, even though the data never leaves your server.

### How accurate are first-party analytics compared to Google Analytics?

Usually more complete, because they aren't blocked as often. In [Plausible's own comparison](https://plausible.io/blog/google-analytics-adblockers-missing-data) on a tech-audience site (first published 2021), Google Analytics missed about 58% of visitors that Plausible counted. Your gap depends on your audience. The trade-off for cookie-free tools is less precise session tracking, since heuristic sessions are not as exact as cookie-based ones.

### Can I use first-party analytics with a static site?

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 own endpoint. For static sites deployed on Temps, add the browser script (ideally served from your own domain) and the proxy handles the `/api/_temps` endpoints.

### What's the performance impact of first-party analytics?

Small. A minimal first-party snippet is well under a kilobyte, uses the non-blocking Beacon API and makes no cross-origin requests, so it adds far less work than a full third-party tag manager setup. Measure with your own Core Web Vitals before and after.

### How does Temps compare to Plausible for self-hosting?

Both are self-hostable and free. The difference is what you're deploying. Self-hosted Plausible is a separate Docker Compose stack (the Plausible application, ClickHouse and PostgreSQL) to maintain, update and back up. Temps includes analytics in the deployment platform you're already running, along with session replay and error tracking. Plausible is cookie-free; Temps sets two first-party cookies.

---

## Stop Giving Away Your Users' Data

Third-party analytics made sense when there were no alternatives. That's no longer the case. You can track what you need (page views, referrers, campaigns, devices) without sending visitor data to an external company.

Whether you build it yourself with the code above, self-host an open-source tool like Plausible or Umami, or use a platform that includes analytics natively, the goal is the same: stop accepting the performance cost, the missing data and the legal exposure that come with third-party scripts.

If you want analytics built into your deployment platform, Temps handles it out of the box. Deploy your app, add one component, and first-party analytics run on your own server, included free with self-hosted Temps.

```bash
curl -fsSL https://temps.sh/deploy.sh | bash
```

---

Source: https://temps.sh/blog/how-to-add-web-analytics-without-third-party-scripts · Index of all pages: https://temps.sh/llms.txt
