Skip to content

Edge Cookie Setup Guide

End-to-end setup and verification guide for Edge Cookie (EC) identity flows.

This guide covers:

  1. Fastly store setup
  2. Partner configuration
  3. Server-to-server batch sync (/_ts/api/v1/batch-sync)
  4. Identity verification (/_ts/api/v1/identify)
  5. Auction bidstream verification (/auction)

Prerequisites

  • Trusted Server deployed and reachable (example: https://trusted-server.example.com)
  • Access to update trusted-server.toml / deployment configuration
  • Fastly CLI authenticated (for store verification)
  • A valid TCF v2 format string (euconsent-v2) for consent-required requests

1) Required Configuration

Generate the passphrase and partner token independently with openssl rand -base64 32, then set EC configuration in trusted-server.toml. The replace-with-* values below are intentionally rejected placeholders:

toml
[ec]
passphrase = "ec_passphrase"
ec_store = "ec_identity_store"

[[ec.partners]]
name = "Mocktioneer SSP"
source_domain = "formally-vital-lion.edgecompute.app"
api_token = "partner_api_token"
bidstream_enabled = true

The passphrase and api_token fields contain keys in the Trusted Server secret store, not the credential values. This workflow calls the inbound identify and batch-sync APIs, so its partner needs api_token. Partners that do not call either API may omit it. Provision high-entropy values under ec_passphrase and partner_api_token; see Configuration.

Required behavior assumptions:

  • The value stored under ec_passphrase is long-lived HMAC-SHA256 keying material for EC ID derivation; use a high-entropy random value of at least 32 characters
  • ec_store is linked to the active Fastly service version
  • ec_store is the only KV-backed EC lifecycle store; it contains identity graph state, minimal consent metadata, source-domain keyed partner UIDs, and withdrawal tombstones
  • Live consent is interpreted from request cookies, headers, geolocation, and policy defaults rather than a separate consent KV store
  • Partners are configured statically in [[ec.partners]] and loaded into an in-memory registry at startup
  • source_domain is the canonical key used for stored IDs and controls EID source matching during ingestion
  • Partner has bidstream_enabled = true if you want user.ext.eids in bidstream

2) Configure Demo Variables

bash
TS_BASE_URL="https://trusted-server.example.com"
MOCK_SSP_URL="https://ssp.example.com"

PARTNER_SOURCE_DOMAIN="ssp.example.com"
PARTNER_NAME="Mocktioneer SSP"
# Use the value provisioned under the partner_api_token secret-store key.
PARTNER_API_KEY="<resolved-partner-api-token>"

# Optional: use a real browser EC if already present
EC_ID="<64hex.6chars>"

TCF_CONSENT="<euconsent-v2-string>"
PARTNER_UID="mock-user-$(date +%s)"

3) Configure Partner

Partners are configured in trusted-server.toml and loaded at startup:

toml
[[ec.partners]]
name = "Mocktioneer SSP"
source_domain = "formally-vital-lion.edgecompute.app"
api_token = "partner_api_token"
bidstream_enabled = true

Provision the bearer token value under partner_api_token, then deploy or restart after changing partner configuration. The token is required for this demo because it exercises the inbound partner APIs.

If you already have an EC from browser traffic, reuse it.

Otherwise, attempt generation with consent:

bash
curl -si "${TS_BASE_URL}/" \
  -H "Cookie: euconsent-v2=${TCF_CONSENT}"

Look for:

  • Set-Cookie: ts-ec=<64hex.6chars>

5) Batch Sync (S2S)

Endpoint: POST /_ts/api/v1/batch-sync

Important: request field is ec_id (full {64hex}.{6alnum} value). The timestamp field remains required for API compatibility, but it no longer orders writes because EC identity entries do not store per-partner sync timestamps. Valid mappings are idempotent last-write-wins: unchanged UIDs are accepted without a write, and different UIDs replace the stored value.

bash
BATCH_UID="${PARTNER_UID}-batch"
NOW_TS="$(date +%s)"

curl -X POST "${TS_BASE_URL}/_ts/api/v1/batch-sync" \
  -H "Authorization: Bearer ${PARTNER_API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{
    \"mappings\": [{
      \"ec_id\": \"${EC_ID}\",
      \"partner_uid\": \"${BATCH_UID}\",
      \"timestamp\": ${NOW_TS}
    }]
  }" | python3 -m json.tool

Expected:

json
{
  "accepted": 1,
  "rejected": 0,
  "errors": []
}

6) Verify Identity

Endpoint: GET /_ts/api/v1/identify

bash
curl -s "${TS_BASE_URL}/_ts/api/v1/identify" \
  -H "Authorization: Bearer ${PARTNER_API_KEY}" \
  -H "Cookie: ts-ec=${EC_ID}; euconsent-v2=${TCF_CONSENT}" | python3 -m json.tool

Expected shape:

json
{
  "ec": "<ec-id>",
  "consent": "ok",
  "degraded": false,
  "source_domain": "ssp.example.com",
  "uid": "mock-user-123",
  "eid": {
    "source": "ssp.example.com",
    "uids": [{ "id": "mock-user-123", "atype": 3 }]
  },
  "cluster_size": 12
}

7) Verify Auction Bidstream Enrichment

Endpoint: POST /auction

bash
curl -si -X POST "${TS_BASE_URL}/auction" \
  -H "Cookie: ts-ec=${EC_ID}; euconsent-v2=${TCF_CONSENT}" \
  -H "Content-Type: application/json" \
  -d '{"adUnits":[{"code":"test","mediaTypes":{"banner":{"sizes":[[300,250]]}}}]}'

Check response headers:

  • x-ts-ec-consent
  • x-ts-eids

For returning users, ordinary page views should not refresh Set-Cookie: ts-ec=.... A Set-Cookie header is expected when the EC is newly generated.

Decode x-ts-eids:

bash
echo "<x-ts-eids-base64-value>" | base64 -d | python3 -m json.tool

Expected decoded payload contains:

  • source = ssp.example.com
  • uids[0].id = <partner-uid>

8) Fastly KV Operational Checks

List stores:

bash
fastly kv-store list

Check service resource links for active version:

bash
fastly resource-link list --service-id <service-id> --version <active-version>

Inspect EC identity entry:

bash
fastly kv-store-entry get --store-id <identity-store-id> --key "${EC_ID}"

If batch sync returns ineligible, check whether the KV entry is missing or has consent.ok = false from a withdrawal tombstone.

9) Troubleshooting Quick Map

SymptomLikely CauseCheck
invalid_token on batch syncWrong partner API keyRe-register partner with known API key
missing field ec_idWrong request schemaUse ec_id field
/_ts/api/v1/identify returns {"consent":"denied"}No consent for current requestSend consent cookie
No uid in /_ts/api/v1/identifyNo successful sync yetRun batch sync or ensure Prebid EID ingestion has populated the partner UID

See also: Edge Cookies, Configuration, API Reference

Released under the Apache License 2.0.