Identity
Datafly Signal manages identity for vendor server-side APIs without loading vendor JavaScript on your site. This page covers the identifier layers Signal maintains, which vendors are covered, and where to configure each.
For the newer identity-graph capabilities, see the dedicated pages:
- Custom Identity Types — declare your own join keys (loyalty ID, CRM ID, …) once per organisation.
- Identity Graph & Join Keys — bind event fields to those types per pipeline; join keys vs attached identifiers.
- Profile Attachment — store person identifiers on receipt, append the full graph on lookup.
- Server & In-Store Sources — join POS/kiosk/backend events to web activity.
The identifier layers
Every event Signal collects is tagged with the relevant identifiers from each of these layers. You don’t configure them per event — Signal selects the right identifiers for each destination automatically based on what the vendor’s API accepts.
1. Anonymous ID (always present)
A stable first-party identifier minted on the visitor’s first event and persisted as a first-party cookie on your domain. The anonymous ID:
- Is the join key for every other identifier (vendor IDs, device ID, user ID).
- Persists across sessions on your domain for a rolling lifetime after the visitor’s last event (refreshed on every response): 400 days by default (the browser maximum), or shorter if your privacy policy requires it. Set it per pipeline in Collector → Identity & cookies → Cookie lifetime (days), 1–400. The device ID cookie follows the same lifetime, and click-ID cookies never outlive it. Until the visitor consents to persistence the cookie is session-only (see Consent).
- Is written in one of three ways, chosen per pipeline under Who sets the anonymous ID cookie:
- Collector and server (default): Datafly.js creates the ID and writes the cookie, and the collection server re-sets the same cookie on every response.
- Server only: the collection server creates the ID and is the only writer of the cookie (
Set-Cookie), which it setsHttpOnlyandSecure. Datafly.js never reads or writes the cookie and never stores the ID inlocalStorage; on every page it learns the ID from the collection server’s first response. Use this where your policy requires identity cookies to be HTTP-only, or forbids JavaScript-written identifier cookies. Match pixels that need the ID (Floodlight, vendor match calls) fire once that first response arrives. - Your website: your website sets the cookie and Signal only reads it. See Using your own visitor ID.
- Carries no PII; it’s a random opaque value.
- Is sent to analytics and warehouse destinations that expect a stable per-visitor identifier (Amplitude
device_id, Mixpaneldistinct_id, BigQueryanonymous_id, etc.).
Using your own visitor ID
If your website already issues its own visitor ID from its servers, Signal can use it as the anonymous ID instead of creating one. Every destination that receives the anonymous ID (analytics device IDs, warehouse tables) then carries the ID your other systems already use, and nothing changes for visitors you already know.
To set it up, in Collector → Identity & cookies:
- Set Anonymous ID cookie to the name of your cookie, for example
visitor_id. - Set Who sets the anonymous ID cookie to Your website (Signal reads it).
- Save. The collector rebuilds automatically.
In this mode:
- Neither Datafly.js nor the collection server ever writes, refreshes or deletes the cookie. Its lifetime, and whether it is set before consent, are decided by your website.
- The whole cookie value is the anonymous ID, so the cookie must hold just the ID (any opaque string, such as a UUID).
- The cookie can be
HttpOnly. Datafly.js then learns the ID from the collection server’s first response. - The collection server must receive the cookie. If collection runs on a subdomain (for example
collect.example.com), set the cookie on your registrable domain (Domain=.example.com). A cookie scoped to one host only reaches collection on that host, unless Datafly.js can read it (notHttpOnly) and send it. - A visitor who has no cookie yet gets an ID that lasts for that page load only, so set the cookie on the page response, before Datafly.js runs.
- Link decoration does not carry the ID to your other domains in this mode, because each domain’s own cookie is its anonymous ID.
For example, in an Express application:
import crypto from 'node:crypto';
// Issue a first-party visitor ID on the page response when the visitor has none.
app.use((req, res, next) => {
if (!req.cookies.visitor_id) {
res.cookie('visitor_id', crypto.randomUUID(), {
domain: '.example.com',
path: '/',
maxAge: 400 * 24 * 60 * 60 * 1000,
secure: true,
sameSite: 'lax',
httpOnly: true,
});
}
next();
});A cookie your website’s own server sets this way is not deleted by Safari’s rule that removes JavaScript-written cookies and storage after 7 days of Safari use without a visit to your site. Because it comes from the server that serves your page, it also avoids the 7-day cap Safari applies to server-set cookies from a host that is a CNAME to another company’s domain or sits in a different IP range.
2. Device ID (optional, per pipeline)
Device recognition is an opt-in capability (off by default) that gives each browser a device ID, _dfdid, and keeps it when the anonymous-ID cookie is replaced. It only runs when the visitor’s consent allows a persistent identifier.
- Enable it per pipeline in Collector → Device recognition.
- The device ID is stored as durably as the anonymous ID. It sits in a server-set cookie on your domain that is renewed on every visit, and the collector keeps a copy in local storage. If one is cleared, the other restores it.
- If both are cleared, Datafly Signal tries to recognise the device from the request itself (network, browser, language, screen and timezone). This recovery works best when the visitor returns soon, on the same network and browser version.
- Mobile apps use the operating system’s device identifier instead (
idfvon iOS,android_idon Android).
3. Authenticated user ID
When your application calls datafly.identify(userId, traits) (web) or Datafly.identify(...) (mobile), the user ID is stitched to the anonymous ID server-side, and:
- All subsequent events for that visitor carry both the anonymous and user IDs.
- The visitor’s prior anonymous events are reattributed to the now-known user in vendors that support back-attribution (Amplitude, GA4 Enhanced Conversions, partner CDPs).
- Optional traits are SHA-256 hashed and sent to vendors that accept hashed PII for matching — email, phone, name, address. Raw PII never leaves your infrastructure. See the hashed-PII coverage table below.
The traits are stored with the shape you sent them, so a nested address object keeps its fields and an integration can read $traits.address.city. Numbers, booleans and arrays keep their types. A later identify() call for the same user updates the traits it sends and keeps the rest; a nested object such as address is replaced as a whole.
Every later event from that visitor (track, page and screen, as well as identify) carries the stored traits as $traits for the integrations to read. An integration only sends a trait its mapping reads, and $traits itself is never sent. Consent decides which integrations can read them:
- An integration whose consent category is granted, or that has no consent category, can read
$traits. - An integration whose consent is denied receives nothing from the event.
- A first-party analytics integration that receives events before consent under the UK DUAA exemption gets the event without
$traitsuntil the visitor grants its consent category. If the visitor refuses that category, it receives nothing. The exemption flags are being replaced by the per-category Before the visitor chooses setting (see Consent), which does the same job. - If your consent settings anonymise an event,
$traitsis removed along with the user ID.
4. Vendor IDs (per destination)
For ad platforms and analytics tools whose server-side APIs accept externally-provided identifiers, Signal generates and maintains the right ID in the right format for the right vendor. You don’t add vendor pixels or JavaScript SDKs to your site to make this work — see the vendor coverage matrix below.
5. Cross-domain ID
If you operate multiple domains as a single customer experience (e.g. brand-a.com + brand-b.com, or marketing.example.com + shop.example.com), Signal can carry the anonymous ID across them so a visitor isn’t seen as two separate users. The Management UI controls which domains are linked and what consent rules apply — see Cross-Domain Identity for setup.
6. Custom identity types (your join keys)
Identifiers your business already owns — a loyalty ID, CRM ID, account number — declared once in Settings → Identity and bound to event fields per pipeline. They join events to people across every channel, including server and in-store sources that have no cookie or device. See Custom Identity Types.
How events resolve to a person
Every event is resolved against the identity graph using a fixed chain — the first identifier that matches an existing person wins:
- User ID (from
identify()or a server event’suserId) - Hashed email
- Hashed phone
- Custom identity types, in the priority order you set (never outranking user ID)
- Device ID
- Cookie ID (the first-party anonymous ID)
Once resolved, the event both extends the person’s profile with any identifiers it carries and gets the person’s known profile appended before delivery — see Profile Attachment.
Vendor ID coverage
Signal handles the right identifier for each vendor server-side. The table groups vendors by how identity is sourced.
Vendor IDs Signal generates and maintains server-side
Signal generates the vendor’s expected ID format on the first event, stores it as a first-party cookie on your domain, and sends it back to the vendor on every subsequent event. The vendor sees a stable identifier without their JavaScript running.
Generation is controlled by the vendor’s Identity Sync toggle on each pipeline: Signal only creates new IDs for vendors whose sync is enabled there. Pipelines without the sync (server pipelines in particular) generate nothing — they attach the person’s existing IDs instead, which is what keeps in-store and backend conversions matching the IDs the vendor saw on the web. See Vendor IDs.
| Vendor | ID(s) maintained | Where it’s sent |
|---|---|---|
| Meta (Facebook) | fbp (browser ID), fbc (click ID) | user_data.fbp / user_data.fbc on Meta Conversions API |
| Google Analytics 4 | client_id | @root.client_id on Measurement Protocol |
| TikTok | ttp (browser ID) | user.ttp on TikTok Events API |
_pin_unauth (browser ID) | user_data.external_id on Pinterest Conversions API | |
| Snapchat | _scid (browser ID) | user_data.sc_click_id / external_id on Snap Conversions API |
liFatId (first-party click-derived) | LinkedIn Conversions API user_data | |
| X (Twitter) | twclid-derived browser ID | X Ads Conversions API |
| Microsoft Advertising | msclkid-derived ID | Microsoft UET / Offline Conversions API |
rdt_uuid (browser ID) | Reddit Conversions API user_data | |
| Amplitude | device_id (aligned with Signal’s anonymous_id) | Amplitude HTTP V2 events |
| Adobe Analytics | marketingCloudVisitorID | Adobe Data Insertion API |
| Adobe Experience Platform | ECID (via Adobe ID) | AEP Streaming Ingestion |
Vendor IDs Signal captures from the browser and forwards
For these, Signal reads existing vendor cookies that were set elsewhere (for example by a server-rendered page or by the customer’s own code) and forwards them with each event.
| Vendor | Cookie read | Notes |
|---|---|---|
| Google Ads | _ga | Aligns Signal events with the existing GA4 client_id |
| Mixpanel | distinct_id | If the customer also uses Mixpanel’s JS for browser-side ID |
Click IDs captured automatically
When a visitor lands on your site from a paid ad, Signal pulls the click ID from the URL and attaches it to every subsequent event for that session:
| URL parameter | Vendor | Used by |
|---|---|---|
gclid | Google Ads | Google Ads Offline Conversions API |
gbraid, wbraid | Google Ads (iOS app/web-to-app) | Google Ads Offline Conversions API |
fbclid | Meta | Conversions API (fbc derived from this) |
ttclid | TikTok | TikTok Events API |
msclkid | Microsoft Advertising | UET / Offline Conversions API |
epik | Pinterest Conversions API | |
ScCid | Snapchat | Snap Conversions API |
li_fat_id | LinkedIn Conversions API | |
twclid | X (Twitter) | X Ads Conversions API |
rdt_cid | Reddit Conversions API | |
irclickid | Impact Radius | Impact partnership conversion tracking |
tduid | Tradedoubler | Tradedoubler sale and lead reporting |
ttdimp, ttd_tdid | The Trade Desk | Real-Time Conversion Events (imp, TDID) and Offline Conversions (click-through macros) |
kgid | Kargo | Kargo conversion attribution |
Partner enrichment
Signal can call a connected CDP server-side on every event, attach resolved profile attributes to the event, and optionally expose an allow-listed subset to the browser as window.datafly.profile.amperity (or the equivalent partner namespace) for client-side personalisation. The Profile API token never touches the browser.
| Partner | Capability | Setup page |
|---|---|---|
| Amperity | Streaming event ingest + Profile API enrichment + browser profile hydration | Amperity |
| Zeotap | Event ingest + identity-graph lookup + profile enrichment | Zeotap |
| LiveRamp | RampID-based identity resolution + Authenticated Traffic Solution | LiveRamp |
Mobile attribution platforms
For mobile apps using the Datafly mobile SDKs, Signal forwards conversion events to the major attribution networks. Each receives the IDFA/AAID (when consent permits), the SDK’s anonymous ID, and the captured click/click-through identifiers.
| Vendor | ID used | Setup page |
|---|---|---|
| AppsFlyer | IDFA/AAID + appsflyer_id | AppsFlyer iOS / Android |
| Adjust | IDFA/AAID + adid | Adjust |
| Branch | IDFA/AAID + Branch identity | Branch |
| Singular | IDFA/AAID + singular_device_id | Singular |
| Kochava | IDFA/AAID + KOCHAVA_DEVICE_ID | Kochava |
Authenticated identity (hashed PII)
When you call datafly.identify(userId, traits), Signal can pass user-provided identity values to vendors that support them for matching — always SHA-256 hashed server-side before delivery. Raw PII never leaves your infrastructure.
| Trait | Hashed and sent to |
|---|---|
email | Meta CAPI, Google Ads Enhanced Conversions, TikTok, LinkedIn, Pinterest, Snapchat, Reddit, X, Microsoft, AEP, HubSpot |
phone | Meta CAPI, Google Ads Enhanced Conversions, TikTok, LinkedIn |
first_name, last_name | Meta CAPI, Google Ads Enhanced Conversions, TikTok |
address.city, address.region, address.postal_code, address.country | Meta CAPI, Google Ads Enhanced Conversions |
date_of_birth | Meta CAPI (db), Google Ads Enhanced Conversions |
gender | Meta CAPI (ge) |
Where to configure it
| What | Where in the Management UI |
|---|---|
| Custom identity types (organisation-wide join keys) | Settings → Identity |
| Identity graph bindings, ID syncs, custom syncs, profile attachment (per pipeline) | Pipelines → select a pipeline → Identity |
| Which vendor IDs to generate / forward per pipeline | Pipelines → select a pipeline → Identity → ID Syncs |
| Device recognition (per pipeline) | Collector → Device recognition |
| Cross-domain identity linkage | Settings → Domains |
| Partner enrichment (Amperity / Zeotap / LiveRamp) | Integrations → install the partner → configure linking keys |
| PII hashing policy (per integration overrides) | Integrations → select an integration → PII Handling |
| Consent gates per ID category | Settings → Consent (canonical categories map your CMP onto Signal’s gates) |
How to verify it’s working
- Open Pipelines → your pipeline → Live Events in the Management UI.
- Trigger a test event on your site (a page view or test conversion).
- Click the event in the live feed; the destination preview shows the exact payload sent to each vendor, identifiers included.
- Cross-reference in the vendor’s own debugger:
- Meta Test Events (Events Manager)
- GA4 DebugView (Admin → DebugView)
- TikTok Events Manager Test Events
- Pinterest Conversions Health
- Snapchat Events Manager Test Events
- …and equivalent tools for each vendor.
For partner-enrichment integrations, the event’s partner_attrs.amperity (or the equivalent partner namespace) block in the live feed shows the attributes resolved on that event.
More detail
Detailed identity architecture, the full supported-vendor matrix, and the underlying mechanisms are shared with customers in the onboarding pack. Contact your account team for the identity reference document.