Web Analytics

Temps records first-party web analytics — visitors, pageviews, custom events, funnels, Core Web Vitals and AI crawler traffic — in the same binary that deploys your app. Wrap a React app in <TempsAnalyticsProvider> (or add one <script> tag to any other site) and pageviews start arriving through the Temps proxy, which stores them on your own server. Session replay is a separate, opt-in feature documented in Session Replay.


Overview

Vercel and most hosting platforms leave analytics to a third-party integration. Temps ships it in the platform, so there is no PostHog or Plausible account to connect. For the product overview, see Temps Analytics.

What's Included

  • Real-time visitor analytics
  • Custom event tracking
  • Core Web Vitals monitoring
  • Funnel analysis
  • Geographic tracking
  • Session stitching
  • AI crawler and bot classification
  • Opt-in session replay (details)

Why It Matters

  • No third-party analytics service
  • Data stays on your server (unless you link the instance to Temps Cloud)
  • Page view capacity scales with your server
  • No per-event or per-seat fees
  • Designed to support GDPR/CCPA compliance — see Privacy & Compliance

Architecture

Temps analytics is powered by:

  • TimescaleDB: the default backend, a PostgreSQL extension whose hypertables partition events by time
  • Optional ClickHouse backend: for high-volume instances (see Observability storage)
  • Batching: the proxy writes request logs in batches, and the replay recorder sends events in batches

Setup

For React and Next.js apps, wrap your application with the React provider:

import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

export function App() {
  return (
    <TempsAnalyticsProvider>
      <YourApp />
    </TempsAnalyticsProvider>
  );
}

For plain HTML pages, Astro, Alpine.js, htmx, or another non-React frontend, add the browser analytics script before </head>:

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

Both options send events to the current site's relative /api/_temps/* endpoints by default. For apps deployed on Temps, the proxy handles those endpoints automatically. The full list of provider props and hooks is in the React Analytics SDK reference; for a step-by-step walkthrough that also adds error tracking and replay, follow Add analytics, errors and session replay.


How does Temps analytics work

Temps identifies visitors with two first-party, HttpOnly cookies set by the Pingora reverse proxy: _temps_visitor_id (kept for 365 days) and _temps_sid (a 30-minute session). The browser SDK sends pageviews and events to the proxy, which attaches those IDs, enriches the event with geography and device data, and writes it to your database. There are no third-party cookies. When Temps is used only as an analytics backend for a site it doesn't serve, the SDK falls back to a visitor ID it keeps in localStorage. In self-hosted mode, analytics data stays on your server; if you link the instance to Temps Cloud (coming soon), configured analytics and OpenTelemetry data is uploaded to Temps Cloud for managed storage and queries. For how events move from the browser to storage, see Data flow; to see which AI crawlers hit your site, see how to track AI crawler traffic.

How this compares with the two analytics tools teams most often replace (competitor details as of October 2026):

TempsPostHog CloudPlausible Cloud
Visitor trackingTwo first-party cookies set by the proxyJS snippet with first-party cookie/localStorageNo cookies (daily rotating hash)
Session replayOpt-in (rrweb, inputs masked)Built-in (5,000 free recordings/mo, then usage-based)Not included
Core Web VitalsBuilt-inBuilt-in (opt-in toggle)Not included
Funnel analysisBuilt-inBuilt-inBusiness plan and up
Data locationYour server (self-hosted) or Temps Cloud (coming soon)PostHog cloudPlausible cloud
PricingFree (self-hosted); Temps Cloud from $29/mo (coming soon)Free up to 1M events/mo, then usage-basedFrom $9/mo
Open-source licenseMIT / Apache 2.0MIT (core) / proprietary (EE)AGPL

For a full side-by-side, see Temps vs PostHog and Temps vs Plausible.


Visitor analytics

Track and analyze visitor behavior with detailed metrics and geographic data.

Metrics Tracked

  • Name
    Page Views
    Description

    Total page views with time-series charts, breakdown by path, referrer tracking

  • Name
    Unique Visitors
    Description

    First-party cookie visitor ID (_temps_visitor_id), session stitching, returning vs new visitor ratio

  • Name
    Session Duration
    Description

    Average session length, time on page, engagement metrics

  • Name
    Bounce Rate
    Description

    Single-page session tracking, exit page analysis

  • Name
    Geographic Data
    Description

    Country, region, city detection using MaxMind GeoIP, timezone tracking

  • Name
    Device & Browser
    Description

    User agent parsing, browser version, OS, device type (mobile/desktop/tablet)

  • Name
    Referrer Sources
    Description

    Traffic source tracking, UTM parameter parsing, campaign attribution

  • Name
    Real-Time Visitors
    Description

    Live visitor count, currently active pages

Dashboard Views

Access analytics data via the dashboard. View real-time metrics, historical trends, and detailed visitor insights all in one place.

Time-Series Charts

View trends over preset ranges (such as the last 24 hours, 7 days or 30 days) or a custom date range. The chart bucket size adjusts to the range you pick.


Bot filtering & engagement

Temps filters out automated traffic so your metrics reflect real humans. Bot detection and engagement scoring are built-in and run automatically — there are no flags, environment variables, or endpoints to configure. The thresholds and pattern list below are fixed in source.

How a session counts as "engaged"

A session is marked engaged only if at least one of these is true:

  • The visitor spent ≥ 10 seconds of measured wall-clock time on the site (MAX(timestamp) − MIN(timestamp) across the session, or last_accessed_at − started_at for the per-session detail view), or
  • The visitor fired a genuine interaction event.

Auto-fired view events do not mark a session engaged on their own, because intersection observers fire them for bots too. The following are excluded from the interaction count:

EventWhy it's excluded
page_viewAuto-fired on every page load
page_leaveAuto-fired when the page is left
Any event name ending in _viewed (e.g. product_viewed)Auto-fired by intersection observers when an element scrolls into view

A session that only fires these view events still becomes engaged if it crosses the 10-second wall-clock threshold — that's the only way such a session counts.

Previously, any event other than page_view / page_leave flipped a session to engaged, which inflated engagement with bot-driven view events. The 10-second-or-interaction rule replaced that as of v0.1.0.

Session replays exclude zero-duration sessions

Replay listings (both the count and the list) only include sessions whose recorded duration is greater than 0 ms. Sessions with a duration of 0 ms or NULL — never-finalized single-burst sessions, which are typically bots — are excluded, because they have nothing to play back.

User-agent bot detection

The events pipeline matches each visitor's user-agent string (case-insensitively, by substring) against a built-in list of 30+ known bot patterns. A match sets the event/visitor is_crawler flag and records the matched crawler_name. A missing or empty user-agent is conservatively treated as a bot.

The pattern list covers:

CategoryExamples
AI crawlersGPTBot, ClaudeBot, anthropic-ai, PerplexityBot, CCBot, Bytespider, Google-Extended, Applebot, Amazonbot
Search / SEO crawlersGooglebot, Bingbot, YandexBot, DuckDuckBot, Baiduspider, AhrefsBot, SemrushBot
Link-preview unfurlersfacebookexternalhit, Slackbot, Discordbot, Twitterbot, LinkedInBot, WhatsApp, Telegrambot
Headless browsers / automationHeadlessChrome, PhantomJS, Puppeteer, Playwright, Selenium
Monitoring toolsPingdom, UptimeRobot, StatusCake
HTTP clientspython-requests, curl, wget, go-http-client, node-fetch, axios
Generic catch-allsbot, crawler, spider

Google-Extended is a robots.txt control token, not a standalone HTTP User-Agent used by Google. Its presence in this general substring filter only means that a client sending that text will be treated as automated traffic; it does not identify genuine Google traffic. The separate AI Agents view uses the proxy taxonomy described below.

This list is matched in addition to the underlying parser's own crawler classification; the substring match is the more specific signal and takes precedence.


Event tracking

Track custom events to understand user interactions and behavior.

Built-in Events

With default settings, the SDK captures these without extra code:

  • Page views (page_view), including client-side route changes
  • Page exits (page_leave)
  • Web Vitals (see Performance monitoring)
  • Engagement heartbeats, used for the engaged-session rule above
  • Clicks on any element with a temps-event-name attribute (declarative tracking, with temps-data-* attributes as properties)

Other interactions — outbound link clicks, form submissions, downloads — are custom events you send yourself. JavaScript errors are captured by error tracking, not analytics: point a Sentry SDK at your Temps DSN as described in Error Tracking. 404s show up as response status codes in your request logs.

Custom Events

Track any custom event in your application:

Track Custom Events

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

function CheckoutButton() {
  const trackEvent = useTrackEvent();

  const handleCheckout = () => {
    trackEvent('checkout_completed', {
      orderId: '12345',
      amount: 99.99,
      currency: 'USD',
      items: 3
    });
  };

  return <button onClick={handleCheckout}>Complete Purchase</button>;
}

Event Properties

  • Name
    Event Name
    Description

    String identifier for the event (e.g., 'signup_completed', 'video_played')

  • Name
    Properties
    Description

    Custom JSON object with event metadata (any structure)

  • Name
    Visitor and Session ID
    Description

    Taken from the _temps_visitor_id and _temps_sid cookies, so events join the visitor's other activity automatically

  • Name
    Timestamp
    Description

    Set by the server when the event is recorded

  • Name
    Context
    Description

    Automatic context (page path, referrer, user agent, screen and viewport size, language, geography)

Querying Events

The project's analytics dashboard lists event names with their counts (the events dimension below); click an event to see its totals, breakdown charts and the visitors who fired it. The same data is available from the API — for example GET /api/projects/{project_id}/events/properties/breakdown for a property breakdown — and through the Node SDK.


Session replay

Session replay is off by default. When you turn it on (enableSessionRecording on the React provider, or data-session-recording="true" on the script tag), the SDK records the page with rrweb: DOM snapshots and mutations, and user input such as clicks, scrolling and typing. All input values are masked by default. The script tag also skips login, signup, checkout, payment and billing paths by default; with the React provider, list those routes in excludedPaths. It does not capture console logs, network requests, or performance data such as FPS or memory, and there are no heatmaps. Recordings are kept for 15 days.

<TempsAnalyticsProvider
  enableSessionRecording
  sessionRecordingConfig={{ sessionSampleRate: 0.1 }} // record 10% of sessions
>
  <YourApp />
</TempsAnalyticsProvider>

Configuration options, privacy controls and the replay player are documented on the Session Replay page. Comparing tools? See Temps vs FullStory and Temps vs LogRocket.


Performance monitoring

Track Core Web Vitals and performance metrics to optimize user experience.

Core Web Vitals

The three Core Web Vitals are LCP, INP and CLS. The SDK also reports FCP and TTFB, and still sends FID, which INP replaced as a Core Web Vital in March 2024.

  • Name
    Largest Contentful Paint (LCP)
    Description

    Core Web Vital. Measures loading performance. Target: < 2.5 seconds

  • Name
    Interaction to Next Paint (INP)
    Description

    Core Web Vital. Measures responsiveness. Target: < 200 milliseconds

  • Name
    Cumulative Layout Shift (CLS)
    Description

    Core Web Vital. Measures visual stability. Target: < 0.1

  • Name
    First Contentful Paint (FCP)
    Description

    Additional metric. Time to first content render. Target: < 1.8 seconds

  • Name
    Time to First Byte (TTFB)
    Description

    Additional metric. Server response time. Target: < 800 milliseconds

Automatic Collection

Web Vitals are collected by default (autoTrackSpeedAnalytics defaults to true), so no extra code is needed. To turn them off:

Disable Web Vitals collection

import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

function App() {
  return (
    <TempsAnalyticsProvider autoTrackSpeedAnalytics={false}>
      <YourApp />
    </TempsAnalyticsProvider>
  );
}

Performance Insights

The project's performance view shows:

  • Each metric over time
  • Percentiles (P75, P90, P95, P99)
  • Breakdowns and filters by page path, device type, browser, operating system and location

Temps does not have performance budgets or Web Vitals alerts. For alerting on server-side signals such as CPU, memory or error rates, use Monitoring.


Funnel analysis

A funnel is an ordered list of events. Temps counts how many visitors reach each step in order, and where they drop off.

Create a Funnel

Create funnels in the project's analytics Funnels view, or through the API. Each step has an event_name and optional event_filter rules (page path, hostname, UTM values, referrer, channel, device type, browser, operating system, language, or a custom event property):

Define Funnel

import { TempsClient } from '@temps-sdk/node-sdk';

const client = new TempsClient({
  baseUrl: 'https://your-temps-instance.com/api', // include the /api prefix
  apiKey: 'your-api-key'
});

await client.funnels.create({
  path: { project_id: 1 },
  body: {
    name: 'Signup Funnel',
    steps: [
      { event_name: 'page_view', event_filter: [{ type: 'page_path', value: '/' }] },
      { event_name: 'page_view', event_filter: [{ type: 'page_path', value: '/signup' }] },
      { event_name: 'signup_form_submit', event_filter: [] },
      { event_name: 'email_verified', event_filter: [] }
    ]
  }
});

Funnel Metrics

  • Name
    Step Conversion
    Description

    Share of visitors from the previous step who reached this step

  • Name
    Drop-off Rate
    Description

    Share of visitors who left at each step

  • Name
    Time Between Steps
    Description

    Average time from one step to the next

  • Name
    Overall Conversion
    Description

    Share of visitors who completed every step

Funnel metrics can be filtered by environment, country and date range.


AI agent tracking

Temps classifies requests whose User-Agent matches its built-in AI-agent taxonomy. For traffic passing through the Temps proxy, no browser SDK or app-side instrumentation is required. User-Agent strings can be spoofed, so this view is for observability—not authentication or proof of downstream model use.

Tracked signals

  • Canonical agent name, provider, and broad purpose
  • Requested paths and request counts
  • Unique source IPs per recognized agent name
  • Request share, response status, and activity over time

Use cases

  • Observe requests carrying recognized identifiers
  • See which paths those requests target most
  • Find crawler requests receiving errors
  • Inspect request activity after publishing llms.txt or sitemap changes

What this data proves:

A matching row proves that Temps recorded a request carrying a recognized User-Agent string. It does not prove that the named provider made the request, indexed the response, used it for training, included it in an answer, or cited it to a user.

Via CLI

# Which recognized AI-agent identifiers appear in requests?
bunx @temps-sdk/cli analytics ai-agents -p my-app --period 7d

# Grouped by AI provider (OpenAI, Anthropic, Google…)
bunx @temps-sdk/cli analytics ai-agents -p my-app --group-by provider

# Which paths receive the most recognized AI-agent requests?
bunx @temps-sdk/cli analytics ai-pages -p my-app --period 30d

# Show the recognized agent split for each path
bunx @temps-sdk/cli analytics ai-pages -p my-app --with-agents

Via REST API

# AI agent breakdown
curl https://your-temps.example.com/api/proxy-logs/stats/ai-agents \
  -H "Authorization: Bearer <token>" \
  -G --data-urlencode "project_id={project_id}" \
      --data-urlencode "start_time=2026-08-01T00:00:00Z" \
      --data-urlencode "end_time=2026-08-08T00:00:00Z"

# Pages crawled by AI
curl https://your-temps.example.com/api/proxy-logs/stats/ai-pages \
  -H "Authorization: Bearer <token>" \
  -G --data-urlencode "project_id={project_id}"

View all dimension data

The overview dashboard shows the top 5 or 10 rows for each chart. To see the full dataset, click the View all button in any chart header.

Dimension pages

Each chart's "View all" button opens a dedicated dimension page at /projects/:slug/analytics/dimensions/:dimension. These pages:

  • Show up to 100 rows for the selected dimension and date range
  • Include an inline text filter for client-side narrowing — useful when a dimension has many distinct values
  • Preserve the currently selected date filter, so navigating to a dimension page and back does not reset your time range

The following dimensions have dedicated pages:

DimensionWhat it shows
pagesTop pages by view count
referrersTraffic sources and referring domains
browsersBrowser distribution
operating_systemsOS distribution
devicesDevice type (desktop, mobile, tablet)
countriesGeographic distribution by country
channelsAcquisition channels (organic, direct, paid, etc.)
eventsCustom event names and occurrence counts
languagesBrowser/OS language preference
utm_sourceUTM source parameter values
utm_mediumUTM medium parameter values
utm_campaignUTM campaign parameter values
utm_termUTM term parameter values
utm_contentUTM content parameter values

Event detail

Rows in the events dimension link through to the event detail view. The event detail page now shows:

  • A first → last timestamp range for that event across all visitors in the selected period
  • Per-visitor columns: visitor UUID, numeric visitor ID, device, browser, location, and referrer

Visitor segments

Clicking any row in a non-page dimension chart — for example "Chrome" in Browsers, "United States" in Countries, an event name, a UTM campaign value, or a referrer — opens a visitor segment page.

Segment pages

Segment pages are located at /projects/:slug/analytics/segments/:dimension/:value and show a paginated list of visitors who match that dimension value within the selected date range:

  • 25 visitors per page, sorted by last action descending
  • Each row links to the individual visitor detail page, where you can see the visitor's full session history, device information, and event timeline
  • The active date filter is carried through the entire navigation chain: overview → dimension page → segment → visitor detail → back

Supported segment filters

The segment visitor list is powered by the /analytics/visitors endpoint, which accepts the following filter parameters:

  • Name
    filter_country
    Description

    Filter visitors by country code (e.g. US, DE)

  • Name
    filter_region
    Description

    Filter visitors by region or state

  • Name
    filter_city
    Description

    Filter visitors by city name

  • Name
    filter_channel
    Description

    Filter visitors by acquisition channel (e.g. organic, direct, paid)

  • Name
    filter_referrer
    Description

    Filter visitors by referring domain or URL

  • Name
    filter_event
    Description

    Filter visitors who fired a specific event name

  • Name
    filter_browser
    Description

    Filter visitors by browser name (e.g. Chrome, Firefox)

  • Name
    filter_os
    Description

    Filter visitors by operating system (e.g. macOS, Windows)

  • Name
    filter_device
    Description

    Filter visitors by device type (desktop, mobile, tablet)

  • Name
    filter_language
    Description

    Filter visitors by browser language preference

  • Name
    filter_utm_source
    Description

    Filter visitors by UTM source value

  • Name
    filter_utm_medium
    Description

    Filter visitors by UTM medium value

  • Name
    filter_utm_campaign
    Description

    Filter visitors by UTM campaign value

  • Name
    filter_utm_term
    Description

    Filter visitors by UTM term value

  • Name
    filter_utm_content
    Description

    Filter visitors by UTM content value

Date filters are preserved across the full navigation chain — overview, dimension pages, segment pages, and visitor detail — so the cohort you are inspecting stays consistent as you drill down and navigate back.


SDKs

Track events from your frontend and enrich visitor records from your backend using the official SDKs.


Privacy & Compliance

Temps analytics is designed to support GDPR and CCPA compliance: the data stays in a database you control and no third party receives it. Whether you are compliant still depends on how you deploy and configure it — your cookie notice, consent flow and retention settings. Temps stores a first-party visitor ID in a cookie and in localStorage, which generally requires consent for EU visitors.

Data Ownership

  • Name
    Self-Hosted
    Description

    Analytics data is stored on your own server and is not sent to Temps or any third party, unless you link the instance to Temps Cloud. Your hosting provider remains a data processor — see Data ownership and privacy.

  • Name
    First-party cookies only
    Description

    The proxy sets two first-party, HttpOnly cookies on HTML responses: _temps_visitor_id (365 days) and _temps_sid (30 minutes). No third-party tracking cookies. When Temps only receives events for a site it doesn't serve, the SDK keeps a visitor ID in localStorage instead.

  • Name
    IP addresses
    Description

    The proxy records the client IP address and user agent with each visitor, for geolocation and bot detection. There is no built-in IP anonymisation setting.

  • Name
    Data Retention
    Description

    On the default TimescaleDB backend, retention is configurable per data type (proxy logs, OTel spans/logs/metrics) via Settings → Monitoring → Data Retention or the settings API. On the optional ClickHouse backend, retention is fixed to table-level TTL. Session replay (15 days) and log aggregator retention (7/30 days) are fixed regardless of backend.

  • Name
    Access and erasure requests
    Description

    Because the data lives in your own database, you can answer access and deletion requests directly. Temps has no dedicated erasure or export endpoint.

To wait for consent before sending analytics events, keep the provider disabled until the visitor accepts:

Consent Mode

import { useState } from 'react';
import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

function App() {
  const [consent, setConsent] = useState(false);

  return (
    <TempsAnalyticsProvider
      disabled={!consent} // Only send events once the user consents
    >
      <CookieBanner onAccept={() => setConsent(true)} />
      <YourApp />
    </TempsAnalyticsProvider>
  );
}

disabled stops the SDK from sending events and replays. The two cookies above are set by the proxy, not the SDK, so list them in your cookie notice.

On the default TimescaleDB backend, data retention windows for proxy logs, OTel spans, OTel logs, and OTel metrics are configurable per data type — see Settings → Monitoring → Data Retention, or PUT /settings. On the optional ClickHouse backend, retention is fixed to table-level TTL and the settings page hides the editable fields accordingly.


Additional Resources

Analytics is one part of Temps' built-in observability: session replay, error tracking and the Observe timeline run on the same server. For the overview, see Observability.

Last updated

Was this page helpful?