---
title: "Auto-properties"
description: "Every $-prefixed property the SDKs and server attach automatically, per platform."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.pug.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Auto-properties

Auto-properties are `$`-prefixed key-value pairs that Pug attaches to every event automatically. The SDK adds them on the client before the event leaves the device; the server adds a second layer during ingestion.

**The `$` prefix is reserved.** Custom event properties you send must not start with `$` — the API rejects any event whose custom property keys begin with `$`. See [Events API](/api/events) for validation details.

You do not need to set auto-properties yourself. Sending them manually has no effect for server-set properties (they are overwritten) and creates duplicates for SDK-set ones.

## SDK-set properties — Web

Set by `@pug-sh/browser` inside `autoProperties` on every event, before the batch is sent to the API.

| Property | Type | Description | Example |
|---|---|---|---|
| `$projectId` | string | Project identifier | `proj_abc123` |
| `$platform` | string | SDK platform — always `web` | `web` |
| `$url` | string | Full URL of the current page (`window.location.href`) | `https://app.example.com/pricing` |
| `$referrer` | string | Document referrer (`document.referrer`); empty string when none | `https://google.com` |
| `$pageTitle` | string | Page title (`document.title`) | `Pricing — Acme` |
| `$locale` | string | Browser locale (`navigator.language`) | `en-US` |
| `$screenWidth` | string | Screen width in CSS pixels (`window.screen.width`) | `1920` |
| `$screenHeight` | string | Screen height in CSS pixels (`window.screen.height`) | `1080` |
| `$sdkVersion` | string | Web SDK version string | `0.0.1` |
| `$browser` | string | Browser name, from `navigator.userAgentData` brands (Chromium) | `Google Chrome` |
| `$browserVersion` | string | Browser major version string | `124` |
| `$os` | string | Operating system / platform | `macOS` |
| `$osVersion` | string | OS version (high-entropy, Chromium only) | `14.4.1` |
| `$device` | string | Device model (high-entropy, Chromium only) | `Pixel 8` |
| `$mobile` | string | `"true"` or `"false"` — whether the UA reports a mobile device | `"false"` |
| `$utmSource` | string | `utm_source` query parameter | `google` |
| `$utmMedium` | string | `utm_medium` query parameter | `cpc` |
| `$utmCampaign` | string | `utm_campaign` query parameter | `spring_sale` |
| `$utmContent` | string | `utm_content` query parameter | `banner_a` |
| `$utmTerm` | string | `utm_term` query parameter | `analytics+software` |

UTM parameters are parsed from `window.location.search` on every event call. `$browser`, `$browserVersion`, `$os`, `$osVersion`, `$device`, and `$mobile` are read from the [User-Agent Client Hints API](https://developer.mozilla.org/en-US/docs/Web/API/User-Agent_Client_Hints_API) (`navigator.userAgentData`) and are only populated in Chromium-based browsers. Firefox and Safari do not expose this API; those browsers get UA properties set by the server-side fallback (see [Server-set properties](#server-set-properties) below). `$platform` has no such fallback — it comes only from the SDK. Other Pug SDKs set the same key with their own value, so you can filter and break down by platform across them; see [Casing differences between SDKs](#casing-differences-between-sdks) for exactly what each one reports.

See [Auto-tracking](/sdks#auto-tracking) for which events trigger automatically.

## SDK-set properties — Flutter

Set by `pug_flutter` inside `autoProperties` on every event. All keys are camelCase.

### Core

| Property | Type | Description | Example |
|---|---|---|---|
| `$projectId` | string | Project identifier | `proj_abc123` |
| `$sdkVersion` | string | Flutter SDK version string | `0.0.2` |
| `$platform` | string | Flutter target platform name (`defaultTargetPlatform.name`) | `android`, `iOS`, `macOS` |
| `$os` | string | Operating system (`Platform.operatingSystem`) | `android` |
| `$osVersion` | string | OS version string | `14` |
| `$locale` | string | Device locale as a BCP 47 language tag | `en-US` |
| `$timezone` | string | IANA timezone identifier (from `flutter_timezone`; falls back to `DateTime.now().timeZoneName`'s abbreviation) | `America/New_York` |
| `$url` | string | Current route name — set when a [`PugRouteObserver`](/sdks#auto-tracking) is wired | `/checkout` |
| `$referrer` | string | Previous route name — set alongside `$url` on navigation | `/cart` |

### Screen

| Property | Type | Description | Example |
|---|---|---|---|
| `$screenWidth` | integer | Logical screen width in dp | `390` |
| `$screenHeight` | integer | Logical screen height in dp | `844` |
| `$screenScale` | number | Device pixel ratio | `3.0` |

### App

| Property | Type | Description | Example |
|---|---|---|---|
| `$appName` | string | App name from `PackageInfo` | `Acme App` |
| `$appPackage` | string | Bundle / package identifier | `com.example.acme` |
| `$appVersion` | string | App version string | `1.4.2` |
| `$appBuild` | string | App build number | `42` |

### Device (populated per platform)

| Property | Platform | Description | Example |
|---|---|---|---|
| `$deviceManufacturer` | Android, iOS, macOS, Linux, Windows | Device manufacturer or OEM | `Apple`, `Samsung` |
| `$deviceModel` | Android, iOS, macOS, Linux, Windows | Device model name | `iPhone 15 Pro`, `Pixel 8` |

The user-assigned device name is deliberately **not** collected — it's PII.

### Network

| Property | Type | Description | Example |
|---|---|---|---|
| `$networkType` | string | Active connectivity type | `wifi`, `mobile`, `ethernet`, `vpn`, `bluetooth`, `other`, `none`, `unknown` |

### Campaign and click-ids

Captured from deep-link URIs when `autoCaptureCampaigns` is enabled. Persisted until the next campaign URL is opened.

| Property | Description | Example |
|---|---|---|
| `$utmSource` | `utm_source` query parameter | `google` |
| `$utmMedium` | `utm_medium` query parameter | `cpc` |
| `$utmCampaign` | `utm_campaign` query parameter | `spring_sale` |
| `$utmTerm` | `utm_term` query parameter | `analytics+software` |
| `$utmContent` | `utm_content` query parameter | `banner_a` |
| `$gclid` | Google Click ID | `Cj0KCQjw...` |
| `$fbclid` | Meta (Facebook) Click ID | `IwAR3x...` |
| `$msclkid` | Microsoft Advertising Click ID | `abc123` |
| `$ttclid` | TikTok Click ID | `Cg8IEAA...` |

See [Auto-tracking](/sdks#auto-tracking) for the navigation events (`screen_view` on mobile, `page_view` on web) emitted when a `PugRouteObserver` is wired.

## SDK-set properties — Node

Set by `@pug-sh/node` inside `autoProperties` on every event, before the batch is sent to the API.

| Property | Type | Description | Example |
|---|---|---|---|
| `$lib` | string | Library identifier — always `pug-node` | `pug-node` |
| `$sdkVersion` | string | Node SDK version string | `0.0.5` |
| `$platform` | string | SDK platform — always `server` | `server` |

That is the complete set. The server SDK has no browser, device, or ambient user, so it sets none of the page, screen, locale, or campaign properties the client SDKs collect — pass anything you need as a custom property on `track()` instead. It also omits `$projectId`: the private key (`prv_…`) it authenticates with is already project-scoped, so there is no project ID to supply at init.

Server-set properties are still added during ingestion, but they describe **your backend rather than your end user** — the request reaches the API from your server, so `$ip` and every geo property derived from it resolve to your server's address. Filter on `$platform = "server"` to keep server events out of geo and browser breakdowns.

## Casing differences between SDKs

Every Pug SDK sets `$platform`, which makes it the one key common to all of them — filter or break down on it to separate traffic by SDK.

| SDK | `$platform` value | Example |
|---|---|---|
| `@pug-sh/browser` | always `web` | `web` |
| `pug_flutter` | Flutter target platform name (`defaultTargetPlatform.name`) | `android`, `iOS`, `macOS` |
| `@pug-sh/node` | always `server` | `server` |

Beyond that key, the Web SDK and Flutter SDK share several property names with identical casing. The table below calls out any divergence so you can write cross-platform queries correctly. **"not set"** = the SDK could supply this but doesn't (a real gap on that platform); **"not applicable"** = the concept doesn't exist on that platform. The Node SDK is left out: it sets only the three properties listed in its section above.

| Concept | Web SDK property | Flutter SDK property |
|---|---|---|
| URL / screen name | `$url` (full URL) | `$url` (current route name; set when `PugRouteObserver` is wired) |
| Page / screen title | `$pageTitle` | not set |
| Referrer | `$referrer` | `$referrer` (previous route name) |
| Platform | `$platform` (always `web`) + `$os` (platform string) | `$platform` (Flutter enum name) + `$os` |
| OS version | `$osVersion` | `$osVersion` |
| Browser | `$browser` | not set |
| Browser version | `$browserVersion` | not set |
| Device model | `$device` | `$deviceModel` |
| Mobile flag | `$mobile` (string `"true"`/`"false"`) | not set |
| Screen width | `$screenWidth` | `$screenWidth` |
| Screen height | `$screenHeight` | `$screenHeight` |
| Locale | `$locale` | `$locale` |
| Timezone | not set client-side | `$timezone` |
| UTM source | `$utmSource` | `$utmSource` |
| UTM medium | `$utmMedium` | `$utmMedium` |
| UTM campaign | `$utmCampaign` | `$utmCampaign` |
| UTM term | `$utmTerm` | `$utmTerm` |
| UTM content | `$utmContent` | `$utmContent` |
| Click-ids | not set | `$gclid`, `$fbclid`, `$msclkid`, `$ttclid` |
| App info | not applicable | `$appName`, `$appPackage`, `$appVersion`, `$appBuild` |
| Network type | not set | `$networkType` |

## Server-set properties

Added by the ingestion server during `BatchCreate`, after the SDK payload arrives. These properties are **never present in the SDK payload** — values sent by clients are ignored or actively stripped.

### Geo enrichment (Cloudflare)

Geo properties come from Cloudflare CDN headers injected at the edge. They are populated only when the API is fronted by Cloudflare with the **"Add visitor location headers"** Managed Transform enabled. Behind other proxies or in self-hosted setups without Cloudflare, these properties will be absent.

| Property | Description | Example |
|---|---|---|
| `$ip` | Client IP address (from `CF-Connecting-IP`, then `True-Client-IP`, then `X-Forwarded-For`) | `203.0.113.1` |
| `$continent` | Continent code | `NA` |
| `$country` | ISO 3166-1 alpha-2 country code | `US` |
| `$region` | Region or state name | `California` |
| `$city` | City name | `San Francisco` |
| `$postalCode` | Postal / ZIP code | `94107` |
| `$metroCode` | Metro code (US DMA) | `807` |
| `$latitude` | Latitude (float64) | `37.7749` |
| `$longitude` | Longitude (float64) | `-122.4194` |
| `$timezone` | IANA timezone name from Cloudflare | `America/Los_Angeles` |

### User-agent enrichment (server-side fallback)

For browsers that do not expose the User-Agent Client Hints API (Firefox, Safari, all iOS browsers), the server parses the `User-Agent` request header and sets these properties. For Chromium browsers the SDK supplies these values directly and they take precedence.

| Property | Description | Example |
|---|---|---|
| `$browser` | Browser family name | `Firefox` |
| `$browserVersion` | Browser version string | `126.0` |
| `$os` | Operating system name | `Mac OS X` |
| `$osVersion` | OS version string | `10.15.7` |
| `$device` | Device family | `iPhone` |
| `$mobile` | `"true"` or `"false"` | `"false"` |

### Bot signals (Cloudflare)

`$bot_score` and `$verified_bot` are **server-only properties**. Any values sent by the client are stripped before enrichment begins; the server then sets them from Cloudflare's `CF-Bot-Score` and `CF-Verified-Bot` headers.

| Property | Type | Description | Example |
|---|---|---|---|
| `$bot_score` | integer | Cloudflare bot score (0–99; lower = more likely bot) | `2` |
| `$verified_bot` | boolean | `true` if Cloudflare identified a known good bot | `false` |

These properties are only populated when Cloudflare is in the request path. In self-hosted deployments without Cloudflare, they will be absent.

## Using auto-properties in queries

Reference any auto-property in Insights filters and breakdowns exactly like custom properties, using the exact key string including the `$` prefix.

**Breakdown by country:**

**Filter to Chrome users only:**

**UTM campaign performance:**

**Exclude bots:**

  <PropertyRow name="Filter" value="$bot_score > 50" />

## Related

- [Events API](/api/events) — event validation rules including the `$`-prefix restriction on custom properties
- [Auto-tracking](/sdks#auto-tracking) — what each SDK captures automatically (Web interactions; Flutter navigation + app lifecycle)

Source: https://docs.pug.sh/reference/auto-properties/index.mdx
