RTB Architecture
Prebid Server Cookie Sync and User Sync Explained: /cookie_sync, /setuid and the uids Cookie
Published · Last updated
Next scheduled review:
Prebid Server cookie sync is how a server-side auction learns each bidder's ID for a browser. Prebid.js calls /cookie_sync, Prebid Server returns sync pixels for bidders it cannot yet identify, and each bidder redirects to /setuid. The server stores the IDs in a uids cookie on its own domain and sends them in later auctions.
Key terms on this page: Prebid Server · cookie sync · user matching · Prebid.js · TCF · GPP · consent string · OpenRTB
Contents
Key facts
- Three endpoints do the work. PBS-Go registers
POST /cookie_sync,GET /setuidandGET /getuids, plus/optoutfor the host's opt-out page (router.go, accessed 9 November 2026). - The defaults differ by build. PBS-Java returns at most 8 syncs per call and turns cooperative sync on by default (application.yaml, accessed 9 November 2026). PBS-Go applies no limit unless the request or account sets one, and cooperative sync is off unless the host enables it (cookie_sync.go, accessed 9 November 2026).
- The cookie lasts 90 days, each ID less. Both builds default the
uidscookie to 90 days (config.go; application.yaml). PBS-Go marks each stored ID as live for 14 days (cookie.go, accessed 9 November 2026). - Some browsers no longer sync at all. Since Prebid.js 11.20.0 (24 June 2026), the Prebid Server adapter skips
/cookie_syncin Safari, in Firefox and Chrome on iOS, and when cookies are denied (setConfig docs; 11.20.0 release). - Current versions. PBS-Go 4.11.1 shipped on 2 November 2026 and PBS-Java 4.5.0 on 4 November 2026 (PBS-Go releases; PBS-Java releases).
Definition
Prebid Server user sync: the process that collects each bidder's own identifier for a browser and stores the bidder-to-ID map in a cookie on the Prebid Server host's domain. The server then passes the right ID to each bidder in OpenRTB user.buyeruid (Prebid.org, User ID Sync, accessed 9 November 2026). Prebid's documentation uses "cookie sync" and "user ID sync" for the same mechanism.
Why server-side bidding needs a sync step
In a browser auction, each bidder's request leaves the reader's browser, so the bidder reads its own cookie. In a server-side auction, Prebid Server calls the bidders from a data centre. No bidder cookie travels with that call. Without a sync, every server-side bid request arrives anonymous, and many buyers bid less or not at all.
The sync gives Prebid Server a lookup table instead. Prebid's own guide states the goal: bidder cookies "must be consolidated under the Prebid Server domain" so they can be sent with auction calls (User ID Sync). The wider trade-off between browser and server auctions is covered in header bidding explained and in our header bidding vs server-side bidding comparison.
Take a news site that moves six bidders to the server. On a reader's first visit, Prebid Server holds no IDs for that browser. The first page view triggers syncs. From the second page view on, each synced bidder sees its own ID in the bid request.
How a sync runs, step by step
- Prebid.js asks for syncs. When
s2sConfigis set, thepbsBidAdapterposts the list of server-side bidders and the privacy signals to/cookie_sync(User ID Sync). The client side is covered in our Prebid.js guide. - Prebid Server picks bidders. It starts with the
bidderslist, or all known bidders if none is sent. It checks theuidscookie, applieslimit, fills spare slots with other bidders ifcoopSyncis true, then appliesfilterSettings(/cookie_sync docs). - The browser fires pixels. Prebid.js drops an image for each
redirectsync and an iframe for eachiframesync. - The bidder reads its cookie. The bidder's sync endpoint reads its own cookie, creating an ID if none exists, and redirects to Prebid Server's
/setuidwith the ID in the URL. - Prebid Server writes the cookie.
/setuidchecks privacy again and, if allowed, adds the ID to theuidscookie (/setuid docs). - The next auction uses it. On a later
/openrtb2/auctioncall, Prebid Server reads the cookie and puts each bidder's ID inuser.buyeruidfor that bidder only.
The /cookie_sync request and response, annotated
This is a request as Prebid.js or a test client might send it. Every field is optional, and all of them can go in the POST body (/cookie_sync docs).
{
"bidders": ["pubmatic", "ix", "openx"],
"gdpr": 1,
"gdpr_consent": "TCF-STRING-FROM-YOUR-CMP",
"gpp": "GPP-STRING-FROM-YOUR-CMP",
"gpp_sid": "2",
"limit": 3,
"coopSync": false,
"account": "1001",
"filterSettings": {
"iframe": { "bidders": "*", "filter": "exclude" }
}
}8 of 8 rows
| Bidders on the page, or the ones you want synced | Omit it and Prebid Server considers all known bidders (docs) |
| 1 if the request is in GDPR scope, 0 if not | Omit it if you do not know; the host's |
| The TCF consent string | Required when |
| GPP string and section IDs | PBS-Go reads the TCF EU section from GPP when present (cookie_sync.go) |
| Maximum sync URLs to return | Capped by the account's |
| Allow syncs for bidders not on this page | Default depends on host settings |
| Prebid Server account ID | Lets account-level sync settings apply |
| Allow or block iframe and image syncs per bidder | The AMP helper uses it to block all iframes |
bidders
- What it does
Bidders on the page, or the ones you want synced
- Note
Omit it and Prebid Server considers all known bidders (docs)
gdpr
- What it does
1 if the request is in GDPR scope, 0 if not
- Note
Omit it if you do not know; the host's
default_valuethen decides
gdpr_consent
- What it does
The TCF consent string
- Note
Required when
gdpris 1
gpp, gpp_sid
- What it does
GPP string and section IDs
- Note
PBS-Go reads the TCF EU section from GPP when present (cookie_sync.go)
limit
- What it does
Maximum sync URLs to return
- Note
Capped by the account's
max_limitin PBS-Go
coopSync
- What it does
Allow syncs for bidders not on this page
- Note
Default depends on host settings
account
- What it does
Prebid Server account ID
- Note
Lets account-level sync settings apply
filterSettings
- What it does
Allow or block iframe and image syncs per bidder
- Note
The AMP helper uses it to block all iframes
Table by AdSovereign, CC BY 4.0.
A typical response lists one entry per bidder that needs a sync. The client must turn each url into an image tag for redirect and an iframe for iframe (/cookie_sync docs).
{
"status": "ok",
"bidder_status": [
{
"bidder": "pubmatic",
"no_cookie": true,
"usersync": {
"url": "https://image8.pubmatic.com/AdServer/ImgSync?p=159706&gdpr=1&gdpr_consent=TCF-STRING&pu=https%3A%2F%2Fpbs.example.com%2Fsetuid%3Fbidder%3Dpubmatic%26uid%3D%23PMUID",
"type": "redirect"
}
}
]
}The sync URL template comes from the bidder's own configuration file. PubMatic's PBS-Go file, for example, declares a redirect URL whose user macro is #PMUID (pubmatic.yaml, accessed 9 November 2026). How those files are structured is covered in Prebid Server bidder adapters.
What /setuid writes, and when it refuses
/setuid takes bidder, uid, gdpr, gdpr_consent and a format flag f. With f=i it returns a 1x1 PNG; with f=b it returns an empty HTML body (/setuid docs). A missing uid deletes that bidder's entry.
GET https://pbs.example.com/setuid?bidder=pubmatic&uid=7C5B3A69&gdpr=1&gdpr_consent=TCF-STRING&f=iIt answers 200 on success, 400 when the request is in GDPR scope and the consent string is missing or invalid, and 451 when privacy rules forbid the cookie (/setuid docs). A 451 is not an error to fix in code. It means the consent check worked.
Decoded, the cookie is plain JSON. PBS-Go stores it base64 URL-encoded under the name uids, with each ID under tempUIDs and its own expiry time (cookie.go). The IDs below are placeholders.
{
"tempUIDs": {
"pubmatic": { "uid": "7C5B3A69-C579-4BB4", "expires": "2026-11-23T10:15:02Z" },
"ix": { "uid": "XE8m2dHM6qQAAAXt", "expires": "2026-11-23T10:15:04Z" },
"openx": { "uid": "f1f4ac13-99f8-46da", "expires": "2026-11-23T10:15:05Z" }
}
}Three timers matter here. The cookie itself expires after ttl_days, 90 by default. Each ID inside it counts as live for 14 days in PBS-Go, after which /cookie_sync asks the bidder again (cookie.go). And when the cookie grows past max_cookie_size_bytes, Prebid Server ejects IDs until it fits; values between 1 and 499 bytes are rejected at startup (config.go).
/getuids returns the same map as {"buyeruids": {...}}. Prebid documents it for publishers whose own servers call Prebid Server and cannot read the cookie (/getuids docs).
Cookie sync settings in PBS-Go and PBS-Java
The two builds expose the same idea under different keys and defaults; their wider differences are in Prebid Server Go vs Java. The table uses the current master branches of both repositories, and account-level values can also live in the account data described in Prebid Server stored requests.
9 of 9 rows
Cookie domain |
|
|
Cookie lifetime |
|
|
Cookie size cap |
|
|
Public URL used in sync redirects |
|
|
Default syncs per call |
|
|
Cooperative sync default |
|
|
Bidder priority groups |
|
|
Block iframe syncs per bidder |
| n/d in config docs |
Sync URL macros |
|
|
Cookie domain
- PBS-Go key (default)
host_cookie.domain(empty, so the request host)- PBS-Java key (default)
host-cookie.domain(not set)
Cookie lifetime
- PBS-Go key (default)
host_cookie.ttl_days(90)- PBS-Java key (default)
host-cookie.ttl-days(90)
Cookie size cap
- PBS-Go key (default)
host_cookie.max_cookie_size_bytes(0, no cap)- PBS-Java key (default)
host-cookie.max-cookie-size-bytes(4096)
Public URL used in sync redirects
- PBS-Go key (default)
external_url(http://localhost:8000)- PBS-Java key (default)
external-url(http://localhost:8080)
Default syncs per call
- PBS-Go key (default)
account_defaults.cookie_sync.default_limit(none)- PBS-Java key (default)
cookie-sync.default-limit(8)
Cooperative sync default
- PBS-Go key (default)
user_sync.coop_sync.default(false)- PBS-Java key (default)
cookie-sync.coop-sync.default(true)
Bidder priority groups
- PBS-Go key (default)
cookie_sync.priority_groupsper account- PBS-Java key (default)
cookie-sync.pri
Block iframe syncs per bidder
- PBS-Go key (default)
cookie_sync.disabled_iframe_bidders(since 4.7.0)- PBS-Java key (default)
n/d in config docs
Sync URL macros
- PBS-Go key (default)
{{.GDPR}},{{.RedirectURL}}- PBS-Java key (default)
{gdpr},{redirect_url}(single braces since 4.0.0)
Table by AdSovereign, CC BY 4.0.
Sources for the table: config.go, usersync.go, account.go, PBS-Go 4.7.0, application.yaml, config-app.md and PBS-Java 4.0.0, all accessed 9 November 2026.
Here is a PBS-Go configuration that sets the cookie on a dedicated subdomain and turns on a bounded cooperative sync. Values marked "yours" are placeholders.
# pbs.yaml (PBS-Go 4.11.x). Env vars use the PBS_ prefix, e.g. PBS_EXTERNAL_URL.
external_url: "https://pbs.example.com" # yours; /setuid redirects are built from this
host_cookie:
domain: "pbs.example.com" # yours; empty means the request host
ttl_days: 90 # default 90; align with your GVL maxCookieAgeSeconds
max_cookie_size_bytes: 4000 # default 0 (no cap); 1-499 fails at startup
user_sync:
coop_sync:
default: true # default false in PBS-Go
cookie_sync:
disabled_iframe_bidders: [] # host-wide list; "*" blocks iframe syncs for all
account_defaults:
cookie_sync:
default_limit: 6 # used when the request sends no limit
max_limit: 10 # caps any limit the request sends
gdpr:
host_vendor_id: 0 # yours: your IAB Europe GVL ID
default_value: "1" # required; "1" treats unknown requests as in scopeThe same intent in PBS-Java, passed with --spring.config.additional-location:
# prebid-config.yaml (PBS-Java 4.5.x)
external-url: "https://pbs.example.com" # yours
host-cookie:
domain: "pbs.example.com" # yours
ttl-days: 90
max-cookie-size-bytes: 4096 # Java default; 0 disables the cap
cookie-sync:
default-limit: 6 # Java default 8
max-limit: 10
coop-sync:
default: true # Java default true
gdpr:
host-vendor-id: 0 # yours: your IAB Europe GVL ID
default-value: "1"Both blocks parse as YAML. Check every key against the version you deploy, because both projects say their configuration source files are the full reference (PBS-Go config.go; PBS-Java config-app.md).
Privacy rules decide whether any sync happens
Prebid Server tests TCF consent for its own host company before it syncs. Responding to /cookie_sync and setting the cookie on /setuid both need Purpose 1 (store or access information on a device) (Prebid Server privacy, accessed 9 November 2026). Without it, /cookie_sync returns no syncs and /setuid fails. Prebid's docs also say a host needs its own Global Vendor List ID for the cookie to be set in GDPR scope.
PBS-Go adds a sharper rule at the endpoint. If gdpr is 1 and no consent string arrives, it rejects the call. If gdpr is missing and the host's default treats requests as in scope, it rejects the call too and tells the client to send gdpr=0 to opt out (cookie_sync.go). The broader EU picture is in GDPR, ePrivacy and the bidstream, and the signal plumbing in GPP and TCF implementation for engineers.
The browser adds a second gate. Since Prebid.js 11.9.0 (29 April 2026), Prebid.js fires no bidder syncs in Firefox or Chrome on iOS, as in Safari. Since 11.20.0, it also skips the Prebid Server /cookie_sync call in those browsers (setConfig docs; 11.9.0 release). For that traffic, server-side bidders must rely on other signals, such as the ID modules discussed in identity after Privacy Sandbox.
Syncing without Prebid.js: AMP and load-cookie
AMP pages run no Prebid.js, so nothing calls /cookie_sync by itself. The host places load-cookie.html on a CDN, and the publisher embeds it in an amp-iframe. The script calls /cookie_sync with max_sync_count, the bidder list and consent, and asks for image syncs only, because AMP does not support iframe syncs (User ID Sync). The script moved from the Prebid Universal Creative repository to the prebid/user-sync repository in July 2024.
<amp-iframe width="1" height="1" title="User Sync"
sandbox="allow-scripts allow-same-origin" frameborder="0"
src="https://cdn.example.com/load-cookie.html?source=amp&endpoint=https%3A%2F%2Fpbs.example.com%2Fcookie_sync&max_sync_count=5">
<amp-img layout="fill" placeholder src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="></amp-img>
</amp-iframe>Mobile apps are different again. Prebid's FAQ says the Prebid SDK has no cookies, so no syncing takes place there (Prebid Server FAQ, accessed 9 November 2026). App traffic is identified through device and ID signals instead.
Who owns the uids cookie
The uids cookie lives on whichever domain serves Prebid Server (User ID Sync). With a managed host, that is the host's domain, and the bidder-to-ID map builds up there across all of the host's publishers. With your own deployment, it is a domain you choose through host_cookie.domain.
That choice has knock-on effects. Cooperative sync makes a large shared host better at matching, because IDs collected on one site help on the next. A single-publisher deployment starts from zero and matches only its own readers. The commercial side of that trade-off is set out in the profiles of Magnite Prebid Server, PubMatic OpenWrap and self-hosted Prebid Server. The build path itself is in the Prebid Server self-hosting guide, and the wider case for owning the sell-side stack is on our publisher independence hub.
Common mistakes
- Leaving
external_urlat its default. PBS-Go builds the/setuidredirect fromexternal_url, which defaults tohttp://localhost:8000(config.go). Every bidder then redirects browsers to localhost, and no cookie is ever written. Set it with the rest of the container settings shown in our AWS and Docker reference setup. - No host GVL ID. PBS-Go logs a warning and skips host GDPR checks when
gdpr.host_vendor_idis 0 (config.go). Prebid's privacy page says the cookie will not be set in GDPR scope without one. Settle this with counsel before launch. - Copying Java sync URLs from old docs. Since PBS-Java 4.0.0, sync URLs use single braces such as
{gdpr}. Templates with{{gdpr}}from older pages no longer resolve (PBS-Java 4.0.0). - Expecting PBS-Go to cap syncs. With no
limitand no account default, PBS-Go returns every bidder that needs a sync. Setdefault_limitso a first page view does not fire dozens of pixels. - Treating 451 as a bug. A 451 from
/setuidmeans the consent check refused the cookie. Measure it as a privacy outcome, not an error rate. - Enabling every adapter with cooperative sync on. PBS-Go enables most bidders by default, so coop sync can return bidders you have no contract with. Prebid recommends disabling unused adapters for this reason (bidder hosting guidelines).
- Counting syncs in Safari. Prebid.js no longer calls
/cookie_syncthere. Segment match-rate reports by browser before you blame the server.
To see the result of a sync, run an auction with "test": 1 and read ext.debug.httpcalls for the bidder's buyeruid. The full debugging workflow is in Prebid Server analytics and debugging.
FAQ
What is cookie sync in Prebid Server?
uids cookie on the Prebid Server domain. Prebid.js calls /cookie_sync, each bidder redirects the browser to /setuid, and later auctions pass the stored ID to that bidder in user.buyeruid (User ID Sync).Why is my Prebid Server match rate low?
external_url points at a public HTTPS host. Prebid's FAQ adds that EEA-heavy traffic and small userSyncLimit values both slow matching (Prebid Server FAQ).Does Prebid Server cookie sync work in Safari?
/cookie_sync in Safari, in Firefox and Chrome on iOS, and when cookies are denied (setConfig docs).What is cooperative sync?
coopSync; the host default is true in PBS-Java and false in PBS-Go unless changed (/cookie_sync docs; application.yaml).How long does the uids cookie last?
host_cookie.ttl_days or host-cookie.ttl-days. Prebid advises matching it to the maxCookieAgeSeconds the host declares in the Global Vendor List (Prebid Server privacy).Does AMP support Prebid Server cookie sync?
load-cookie.html page served in an amp-iframe. It calls /cookie_sync and returns image syncs only (User ID Sync).How this works on owned infrastructure
The question on this page is who holds the map between your readers and each buyer's ID. With a rented Prebid Server, the uids cookie sits on the vendor's domain and the sync logs sit in the vendor's systems. AdSovereign runs the sell-side stack, Prebid Server included, on servers or a cloud account you control, so the cookie domain, the consent checks on /setuid and the sync records stay under your own configuration and retention rules. You still need a lawful basis and a GVL decision; the software does not settle either. The architecture page shows where the sync endpoints sit, and security covers how logs and keys are handled.
Sources
- Prebid.org, "Prebid Server User ID Sync" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/developers/pbs-cookie-sync.html
- Prebid.org, "Prebid Server Endpoints: /cookie_sync" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/endpoints/pbs-endpoint-cookieSync.html
- Prebid.org, "Prebid Server Endpoints: /setuid" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/endpoints/pbs-endpoint-setuid.html
- Prebid.org, "Prebid Server Endpoints: /getuids" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/endpoints/pbs-endpoint-getuids.html
- Prebid.org, "Prebid Server Privacy Features" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/features/pbs-privacy.html
- Prebid.org, "Bidder-Specific Hosting Guidelines" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/hosting/bidder-specific-guidelines.html
- Prebid.org, "Prebid Server FAQ" (accessed 9 November 2026). https://docs.prebid.org/faq/prebid-server-faq.html
- Prebid.org, "pbjs.setConfig: Configure User Syncing" (accessed 9 November 2026). https://docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html
- GitHub, prebid/prebid-server,
router/router.go,endpoints/cookie_sync.go,usersync/cookie.go,config/config.go,config/usersync.go,config/account.go,static/bidder-info/pubmatic.yaml(master, accessed 9 November 2026). https://github.com/prebid/prebid-server - GitHub, prebid/prebid-server-java,
src/main/resources/application.yamlanddocs/config-app.md(master, accessed 9 November 2026). https://github.com/prebid/prebid-server-java
More sources (3)
- GitHub, prebid/prebid-server releases v4.7.0 (20 July 2026) and v4.11.1 (2 November 2026). https://github.com/prebid/prebid-server/releases
- GitHub, prebid/prebid-server-java releases 4.0.0 (6 August 2026) and 4.5.0 (4 November 2026). https://github.com/prebid/prebid-server-java/releases
- GitHub, prebid/Prebid.js releases 11.9.0 (29 April 2026) and 11.20.0 (24 June 2026). https://github.com/prebid/Prebid.js/releases