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.
The _dfid Cookie
| Attribute | Value |
|---|---|
| Name | _dfid |
| Format | UUID v4 (e.g. f47ac10b-58cc-4372-a567-0d02b2c3d479) |
| Set by | Set-Cookie response header from Ingestion Gateway |
| Domain | Customer’s subdomain (e.g. .example.com) |
| Path | / |
| httpOnly | true |
| Secure | true |
| SameSite | Lax |
| TTL | 400 days |
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 400-day TTL across all browsers, including Safari.
JavaScript-set cookie: document.cookie = "_dfid=abc; max-age=34560000"
→ Safari ITP caps this at 7 days (or 24 hours)
Server-set cookie: Set-Cookie: _dfid=abc; Max-Age=34560000; HttpOnly; Secure; SameSite=Lax
→ Full 400-day lifetime in all browsersThis 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=34560000; HttpOnly; Secure; SameSite=Lax; Path=/
- JSON response body: { "success": true }
6. Browser stores the _dfid cookie automaticallyThe 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 attachedThe gateway refreshes the cookie TTL on every request, so active visitors never lose their identity due to cookie expiration. The 400-day TTL effectively means “400 days 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-0d02b2c3d479This 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.
Device Recognition: Recovering Lost Identity
If a visitor clears their cookies and localStorage, the _dfid is lost. On their next visit, the gateway would normally generate a new UUID — making the visitor appear as a brand-new user.
When Device Recognition is enabled, the Ingestion Gateway checks server-side signals (IP, User-Agent, Accept-Language, screen resolution, timezone, locale) against a store of known device hashes. If a match is found, the gateway restores the visitor’s previous _dfid instead of generating a new one.
The restored identity is communicated back to Datafly.js via a corrected_anonymous_id field in the event response. Datafly.js updates its local identity stores (localStorage, sessionStorage) so all subsequent events use the corrected ID.
Visitor clears cookies → returns to site
→ Gateway: no _dfid cookie, generates new UUID
→ Gateway: computes device hash, finds match in Redis
→ Gateway: overrides new UUID with stored anonymous_id
→ Gateway: sets _dfid cookie with restored ID
→ Response: { "corrected_anonymous_id": "original-uuid" }
→ Datafly.js: updates localStorage with corrected IDDevice Recognition is opt-in and disabled by default. See Device Recognition for configuration details and privacy safeguards.
Cookie Scope and Subdomains
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 siteshop.example.com— e-commerce storefrontblog.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.