IdentityAnonymous ID

Anonymous ID

The anonymous ID is the foundation of Signal’s identity system. Every visitor to your site receives a persistent, server-generated identifier stored in the _dfid first-party cookie. This ID serves as the primary key for all identity lookups, vendor ID associations, and cross-session stitching.

AttributeValue
Name_dfid
FormatUUID v4 (e.g. f47ac10b-58cc-4372-a567-0d02b2c3d479)
Set bySet-Cookie response header from Ingestion Gateway
DomainCustomer’s subdomain (e.g. .example.com)
Path/
httpOnlytrue
Securetrue
SameSiteLax
TTL2 years

Why Server-Set Matters

The _dfid cookie is set via the HTTP Set-Cookie response header — not by JavaScript. This distinction is critical for Safari users.

Safari’s Intelligent Tracking Prevention (ITP) caps the lifetime of cookies set by JavaScript (document.cookie) to 7 days. In some cases, ITP reduces this further to 24 hours if the referring domain is classified as a tracker. Cookies set via Set-Cookie headers from a first-party server are exempt from these restrictions and persist for their full configured TTL.

Because the Ingestion Gateway runs on the customer’s own subdomain (e.g. data.example.com), the _dfid cookie is a genuine first-party cookie set by the first-party server. It persists for the full 2-year TTL across all browsers, including Safari.

JavaScript-set cookie:   document.cookie = "_dfid=abc; max-age=63072000"
                          → Safari ITP caps this at 7 days (or 24 hours)

Server-set cookie:       Set-Cookie: _dfid=abc; Max-Age=63072000; HttpOnly; Secure; SameSite=Lax
                          → Full 2-year lifetime in all browsers

This is the same reason Signal sets all vendor cookies (_ga, _fbp, _ttp, etc.) via server-side Set-Cookie headers rather than injecting them with JavaScript. Every cookie Signal manages benefits from ITP exemption.

First Request Flow

When a new visitor arrives on your site for the first time, the following sequence occurs:

1. Browser sends request to your site
2. Datafly.js fires a page event to the Ingestion Gateway
3. Gateway checks for _dfid cookie in the request headers
4. No _dfid found → Gateway generates a new UUID v4
5. Gateway responds with:
   - Set-Cookie: _dfid={new-uuid}; Max-Age=63072000; HttpOnly; Secure; SameSite=Lax; Path=/
   - JSON response body: { "success": true }
6. Browser stores the _dfid cookie automatically

The UUID v4 is generated using a cryptographically secure random number generator (crypto/rand in Go). There is no sequential or predictable component.

Subsequent Request Flow

On every subsequent page load or event, the browser automatically includes the _dfid cookie in requests to the Ingestion Gateway (because it is a first-party cookie on the same domain):

1. Browser sends event to Ingestion Gateway
   Cookie: _dfid=f47ac10b-58cc-4372-a567-0d02b2c3d479
2. Gateway reads _dfid from the Cookie header
3. Gateway refreshes the cookie TTL by re-sending the Set-Cookie header
4. Gateway uses the _dfid as the anonymous_id in the event payload
5. Event is published to Kafka with anonymous_id attached

The gateway refreshes the cookie TTL on every request, so active visitors never lose their identity due to cookie expiration. The 2-year TTL effectively means “2 years since last visit.”

Identity Lookup Key

The _dfid value is used as the primary key in Redis for all identity-related data:

Redis key: identity:{anonymous_id}

Example:   identity:f47ac10b-58cc-4372-a567-0d02b2c3d479

This Redis hash stores all associated vendor IDs, click IDs, and enrichment results for the visitor. When the Event Processor prepares an event for delivery, it looks up this hash to retrieve the vendor-specific IDs needed for each integration.

HGETALL identity:f47ac10b-58cc-4372-a567-0d02b2c3d479

→ ga_client_id     "1234567890.1708876543"
→ fbp              "fb.1.1708876543000.9876543210"
→ fbc              "fb.1.1708876543000.IwAR3x..."
→ ttp              "a1b2c3d4e5f6g7h8i9j0k1l2m3n"
→ gclid            "CjwKCAjw..."
→ user_id          "user_98765"
⚠️

The _dfid cookie is httpOnly, which means client-side JavaScript cannot read its value via document.cookie. This is intentional — it prevents XSS attacks from exfiltrating anonymous IDs. Datafly.js does not need to read the cookie directly; the browser sends it automatically with every request to the Ingestion Gateway.

Linking to Known Users

When a visitor authenticates and your application calls datafly.identify('user_98765', { ... }), the Ingestion Gateway stores the mapping between the anonymous ID and the known user ID:

HSET identity:f47ac10b-58cc-4372-a567-0d02b2c3d479 user_id "user_98765"

This allows all historical events collected under the anonymous ID to be associated with the known user. Delivery Workers include both the anonymous ID and the user ID in outbound payloads when the vendor API supports it.

The _dfid cookie is set on the customer’s root domain (e.g. .example.com), which means it is shared across all subdomains:

  • www.example.com — main site
  • shop.example.com — e-commerce storefront
  • blog.example.com — content site

All subdomains share the same _dfid value as long as they send events to the same Ingestion Gateway endpoint. For cross-domain identity (e.g. example.com to different-brand.com), see Cross-Domain Identity.