The Data Exhaust of a Single Page Load: What Leaves the Browser, and What It Reveals
Follow a publisher page through requests, storage, identifier syncing, and inference, then learn how to audit the evidence without overstating what a browser trace proves.
- The invisible auction
- From campaign budget to publisher payment
- Who decides which ad gets served?
- The millisecond handshake
- Anatomy of an OpenRTB auction
- Campaign lifecycle inside a DSP
- Trusting the programmatic supply chain
- ML in the millisecond
- A real-time ad platform under a millisecond budget
- The data exhaust of a page load You are here
- The post-cookie frontier
- Practical privacy on the web
- Learning the win curve
- From win curve to bidding
- Floor-price optimization
- What did the ad actually cause?
Priya opens Wanderlust Weekly’s guide to weekend treks. She sees a headline, a photograph, a privacy prompt, and eventually an advertisement for Urban Hiker’s boots. The page feels like one interaction with one publication.
The browser’s account is different. It retrieves code from other hosts, sends event messages, receives instructions to contact more services, and may attach identifiers to those requests. Some recipients can connect this visit to earlier observations. Others can learn something useful without identifying Priya at all.
The real-time platform article ended inside the bidder, deciding what to do with a request it had already received. Here we step back to the browser that produced that request. The supply-chain investigation asked who was authorized to sell the impression; now we follow the data ledger: what information leaves, where it goes, and which conclusions the evidence supports.
Our example is a constructed teaching trace, not a measurement of a live publisher. All names, domains, identifiers, timestamps, and counts are synthetic. We will also build a procedure for investigating a real page. Keeping those two things distinct matters: a convincing network diagram is not evidence that a particular company collected a particular person’s data.
1. Define the Visit Before Counting Its Requests
“What does this page collect?” sounds like a question with one answer. In practice, the answer depends on how we arrive.
A returning browser can bring identifiers that a fresh profile lacks. A saved privacy choice can change which scripts initialize. Browser protections, extensions, login state, geography, experiments, and the current ad response can all change the resulting traffic.
For our teaching visit, assume a desktop browser with a publisher session and existing identifiers at two advertising services. Optional advertising and analytics wait for a choice. At 900 ms, Priya permits those optional purposes. The identifier-matching example assumes the browser permits the relevant cookies in that context. These are stated conditions of the example, as is the ordering that follows, with optional collection starting only after the 900 ms choice; section 7 shows how to test that ordering on a real page rather than assume it.
We use a ten-second observation window after navigation, without scrolling or clicking the ad. That boundary excludes later activity rather than proving there is none. A background tab, a scroll, or a subsequent purchase would be a different observation.
The selected events look like this:
| Time from navigation | Browser request | Initiated by | Evidence available in the browser |
|---|---|---|---|
| 0 ms | wanderlust.example/weekend-treks | Navigation | Page URL, request headers, eligible publisher cookies |
| 45 ms | choices.example/cmp.js | Page markup | Retrieval of code for the privacy interface |
| 930 ms | metrics.example/collect | Analytics code after the choice | A page-event payload and its destination |
| 940 ms | ssp-a.example/auction | Publisher advertising code | Slot, context, privacy signals, and any included identifiers |
| 1,010 ms | match-a.example/start | Advertising integration | The beginning of a browser-mediated matching chain |
| 1,030 ms | match-b.example/match?a=A17 | Redirect response | Identifier A17 carried to B; B’s own cookie if available |
| 1,260 ms | verify.example/event | Creative measurement code | A reported rendering-related event |
“Eligible” here and below means cookies the browser is willing to attach to that request under its scope and policy rules. The table selects events rather than counting every request: images, stylesheets, fonts, script dependencies, creative retrieval, and other events are omitted. The times illustrate ordering, not latency benchmarks. The measurement request also does not, by itself, establish that the ad met a viewability standard.
The practical unit of analysis is a request under stated conditions, not a domain appearing somewhere in a blocklist.
2. One Page Can Have Many Recipients
The initial request reaches the publisher’s serving infrastructure. Page instructions can then cause the browser to contact other destinations. A downloaded script may initiate still more requests, while a redirect response can supply the next URL without page JavaScript choosing it directly.
We should retain the initiator relationship alongside the destination. It helps distinguish a service explicitly loaded by the page from one brought in by a tag, a creative, or a redirect. Chronological proximity alone does not prove that one request caused another.
Figure 1. The browser sees its connections, not the whole network. Browser-visible destinations are the beginning of the recipient map. The selling service’s downstream distribution requires separate evidence; it is not revealed by counting browser requests.
The distinction is especially important for bidding. A browser may send one auction request to a selling service, which may distribute information to several buyers on its servers. The browser’s Network panel records the first connection, not the server-side fan-out described in our OpenRTB article; the bid request examined there is one of those server-side copies, and the three-DSP fan-out drawn in our introduction happens entirely inside the dashed region of Figure 1.
We therefore separate three statements:
- Observed: the browser attempted a request to this host with these fields.
- Corroborated: integration records or service logs establish which system handled it and what happened next.
- Unknown: downstream copying, retention, enrichment, or use is not established by this capture.
Even the first statement needs care. A blocked request entry is evidence of an attempted action, not necessarily successful transmission. A cached resource may appear in the inspection workflow without a fresh server fetch. A successful response is stronger evidence that the endpoint handled a request; its retention practices stay in the unknown column.
A hostname is not a corporate identity
metrics.wanderlust.example might be served by the publisher or delegated to a vendor. A hostname outside the publisher’s domain might serve an ordinary image, a security function, or an advertising endpoint. Different hosts can belong to one operator, and one hosting provider can serve unrelated customers.
For a real audit, we would record the requested hostname, its technical hosting or delegation evidence, the attributed service operator, and the source supporting that attribution. Publisher disclosures, vendor documentation, contracts, and infrastructure records answer different parts of that investigation. A DNS alias alone does not establish every downstream recipient or purpose.
“Eight third-party hosts” is a useful inventory fact. It is not equivalent to “eight companies built an advertising profile.”
3. Read the Message, Not Just Its Destination
At 930 ms, the analytics script sends the following JSON body to https://metrics.example/collect:
1
2
3
4
5
6
7
8
9
{
"event": "page_view",
"page": "https://wanderlust.example/weekend-treks",
"visit_id": "v-204",
"language": "en-IN",
"timezone": "Asia/Kolkata",
"viewport": {"width": 1365, "height": 768},
"privacy_state": "optional-allowed"
}
The field names belong to this application rather than a standard analytics protocol, and privacy_state is an application label, not a valid replacement for an industry consent string such as a TCF string. The script obtained visit_id from publisher-origin storage and deliberately included it in the payload.
Several kinds of information travel together here:
| Information | How the recipient obtains it | What it establishes |
|---|---|---|
| Page URL | Explicit payload field | The sender reported this page context |
| Visit identifier | Explicit payload field | Events carrying the same value can be grouped within its defined scope |
| Language, timezone, viewport | Script reads and transmits browser-exposed values | Reported characteristics of this execution environment |
| Cookies, if eligible and included | Browser request handling | State scoped to the destination and applicable browser rules |
| Network address visible to the receiving infrastructure | Connection metadata | The apparent source of that connection, which may be a proxy or relay |
There is no name or email in the body. Nevertheless, the page and visit ID can support a behavior record. Adding a later event with the same ID can extend that record even if no recipient knows Priya’s civil identity.
JavaScript need not place the network address in this JSON: the receiving edge sees its connection peer; what an application behind that edge receives depends on proxying and forwarding. Likewise, IP-derived location is an uncertain inference about a network exit, not proof that Priya lives in Bengaluru or that two requests behind a shared address came from one person.
Referrer policy does not sanitize an application’s payload
Suppose the page uses Referrer-Policy: strict-origin-when-cross-origin. For this HTTPS cross-origin request, the browser’s Referer header ordinarily supplies only the publisher origin, https://wanderlust.example/, rather than the article path. That behavior is described in MDN’s referrer-policy reference.
Yet the JSON above explicitly supplies the full page URL. The referrer policy governs only the browser-generated referrer information; a page URL that application code places in a body or query parameter passes through untouched. An audit that checks only the Referer header could miss the more informative copy.
The same distinction applies to HTTPS. Encryption protects the message in transit from parties unable to decrypt that connection; the service terminating it still sees the request. “Encrypted” and “not shared with this recipient” are different claims.
For Priya’s trekking page, the context may seem ordinary. On a page about debt, fertility, addiction, or a workplace dispute, an equally ordinary page_view event can expose a much more sensitive context. The sensitivity travels in the contents, not the event name.
4. Storage Matters, but Execution Context Matters Too
Cookies and browser storage are often grouped together as “trackers.” That hides an important mechanical difference.
For cookies, the browser can attach matching values to eligible requests, subject to scope, attributes, credentials behavior, and browser policy. HttpOnly prevents page JavaScript from reading a cookie; it does not stop the browser sending that cookie on an eligible request. These mechanics are covered in MDN’s cookie guide.
Local storage does not automatically become an HTTP request header. Code must read a value and transmit it for a remote recipient to receive that value. In our analytics example, the transmission happens when the script places v-204 in its event body.
We therefore need two pieces of evidence: what was stored and which outgoing request, if any, carried a copy. A persistent value in storage indicates a capacity for continuity; each actual use of that value needs its own evidence.
A third-party script can execute as part of the publisher page
Imagine the page includes ordinary script code downloaded from metrics.example. Once included in the publisher document, that script runs in the document’s context. Its storage access follows that document rather than the domain that hosted the JavaScript file. A cross-origin iframe is different: its document normally has its own origin and cannot simply read the parent document’s storage. MDN’s Web Storage documentation explains this distinction.
Figure 2. Where code runs determines which storage it can access. The code’s download host and its execution context answer different questions. A local-storage value reaches a recipient through an explicit transmission; it is not automatically attached like an eligible cookie. Both reads remain subject to browser and document restrictions.
This is why counting only third-party cookies misses part of the story. A vendor integration can work with a publisher-scoped identifier and submit events to a collection endpoint. Whether it actually does so must be checked in code or traffic, not inferred merely from the script’s presence.
The same-origin policy restricts important forms of access, particularly reading another origin’s data, while browsers still support cross-origin embeds and certain outgoing requests. A blocked cross-origin response read is not enough to conclude that the server received no request. Depending on the request, a failed preflight may instead prevent the subsequent application request from being sent.
Partitioning changes which visits share state
Storage partitioning can separate an embedded service’s state by the top-level site. The same service embedded on a travel site and a news site may then have different state compartments. MDN’s state-partitioning guide describes this separation and its access considerations.
We should record which browser, mode, storage mechanism, and permissions the audit uses. A matching demonstration that assumes unpartitioned cookies does not show that the same flow works under partitioning or blocking. Nor does cookie blocking prove that URL parameters, login-based identifiers, or publisher-to-server transfers disappeared.
5. A Redirect Can Translate Two Identifiers
Suppose Match A recognizes this browser as A17, while Match B recognizes it as B92. Each ID belongs to its own namespace. Without an additional relationship, A’s records and B’s records cannot simply join on those unequal strings.
A browser-mediated matching flow can supply the relationship. Under our example’s stated cookie-access conditions:
- The browser requests
https://match-a.example/start, attaching A’s eligibleaid=A17cookie. - A returns a redirect whose destination is
https://match-b.example/match?a=A17. - The browser follows it, carrying
A17in the URL and attaching B’s eligiblebid=B92cookie to the request to B. - B now receives both identifiers and can store the mapping
(A17, B92).
The flow is simplified rather than any vendor’s actual protocol; Google’s cookie-matching documentation provides a concrete example of the broader matching mechanism and its integration requirements.
Figure 3. A redirect can bridge two identifier namespaces. A’s cookie is not sent as B’s cookie: its identifier is explicitly copied into a URL that B receives alongside B’s own state.
B gains no direct access to A’s cookie jar; the transfer is explicit in the redirect URL. The flow also does not establish that A received B92; a reverse mapping would require another message or a different arrangement.
The most useful audit record is therefore the whole chain: original request, response Location, redirected request, attached cookies, and any subsequent callback. Merely labeling both endpoints “tracking pixels” loses the join that explains their significance.
If B’s cookie is absent, the illustrated request does not establish the mapping to the existing B92. B might create new state, perform a different matching process, or decline the operation. Telling those apart requires additional evidence, not filling the missing identifier with the result we expected to find.
A mapping can allow observations made under different IDs to be combined. How long the mapping is kept, which records are actually joined, and whether another recipient receives it are follow-up questions for system logs, data inventories, and retention controls.
6. No Stable Identifier Does Not Mean No Information
Now remove the shared identifiers from Priya’s visit. A recipient could still receive page context, language, timezone, viewport dimensions, request timing, and network information. It may classify the page as outdoor content without trying to recognize a returning browser.
Context classification and identity linkage are different operations. “This page discusses trekking” can support an ad-selection decision. “This event belongs to the same browser as yesterday’s event” requires another kind of evidence. “This reader is planning a purchase” is a further inference, and may be wrong even when the first two statements are correct.
Browser fingerprinting combines distinguishing characteristics to support recognition. Inputs can include language, timezone, browser or device characteristics, and rendering-related signals, with availability affected by browser protections. MDN’s fingerprinting overview describes the mechanism. An observed screen-size read alone does not prove fingerprinting: responsive layout also needs dimensions. We must examine which values are collected, combined, transmitted, and used.
Combining clues can narrow a set without proving identity
Consider a reference set of 1,000 browser observations. Of these, 600 share the observed timezone. Within those 600, 240 also share the language setting. Of those 240, 18 also share a particular viewport measurement.
We stipulated these nested counts rather than measuring uniqueness rates. They show why individually common attributes can become more selective together. They do not let us multiply unrelated marginal percentages as though the attributes were independent. The reference set of 1,000 is itself a choice: the same three attributes narrow a set of one million observations very differently, so “18” is a statement about this population, not about Priya.
Figure 4. Common clues become more selective in combination. Combining observations changes the candidate set. Eighteen matches in this constructed dataset are neither eighteen identified people nor a calibrated probability that two events share an owner.
Even one remaining candidate would establish uniqueness only within that reference set and those measurements. Browser upgrades, resized windows, shared devices, spoofed values, and an incomplete comparison population can all complicate linkage. Precision must be evaluated rather than inferred from a small final count.
The consequences also differ by mistake. A false match can attach someone else’s behavior to Priya’s record; a missed match can fragment a record across IDs. Our identity article examines those errors. Here the narrower lesson is that data stripped of a name or a cookie may still support sensitive conclusions.
7. A Privacy Choice Is an Event to Verify
Our trace says optional collection began after the 900 ms choice. A real audit must establish both the choice and the subsequent behavior rather than trust the presence of a banner.
Industry privacy signals, such as those carried by the IAB Tech Lab’s Global Privacy Protocol (GPP) specifications, communicate consent and preferences between systems. A transmitted string is evidence of a declared state, not proof that every recipient interpreted it correctly, restricted processing, or deleted an earlier copy.
For a useful comparison, we can define three runs:
| Run | Starting condition | Action | Main comparison |
|---|---|---|---|
| A | Fresh, documented profile with no saved choice | Leave the prompt untouched | What starts before a choice? |
| B | Equivalent fresh profile | Reject optional purposes | What still starts after rejection? |
| C | Equivalent fresh profile | Accept the same optional purposes | Which destinations, payloads, and storage changes are added? |
Fresh profiles make the starting state clearer but do not represent every returning visitor. We should separately test a reload with a saved rejection and, if relevant, withdrawal after acceptance. Withdrawal addresses future behavior under the implementation, while bytes already sent remain with their recipients.
The comparison needs more than total requests. A rejected visit can still load publisher content, security services, or the privacy interface itself. Conversely, two runs can make the same number of requests while transmitting very different identifiers or URLs. The useful differences are destination, purpose, payload, storage access, and timing relative to the choice.
Repeated runs help expose auction variability, asynchronous behavior, and experiment assignment. If an endpoint disappears only once, we should not immediately credit the privacy setting. Keep browser settings, login state, page interactions, and observation windows aligned, and report remaining sources of variation.
An unexpected pre-choice request deserves investigation, not an instant legal conclusion. Establish what was sent, whether it reached the destination, its purpose, and the applicable configuration. The technical trace supports the inquiry; a legal assessment needs facts beyond it.
8. Build an Audit Another Person Can Repeat
We can turn the walkthrough into a small evidence packet. The browser tools reveal a great deal, provided we preserve the conditions and avoid confusing absence from a view with absence from the system.
Start with an isolated test profile and a non-sensitive page. Record browser version, mode, extensions, tracking settings, login state, approximate region, and privacy-choice state. Record the page URL, start time, duration, and interactions. A fresh profile and a returning profile answer different questions, so label them explicitly.
Open developer tools before navigation. In the Network panel, preserve the log across redirects, record the requests, and inspect initiators, headers, payloads, responses, and cookies. Inspect storage separately before and after. Note whether cache was enabled and whether requests were blocked or served locally. Chrome’s Network reference documents these inspection and export facilities.
For each material event, record:
- Destination and operator: the host, attributed organization, and evidence for that attribution.
- Trigger and timing: page code, tag, creative, redirect, or user action; before or after which privacy state.
- Data: meaningful URL parameters, body fields, eligible identifiers, and the relevant storage source where established.
- Outcome and limits: attempted, blocked, responded, or served locally; downstream behavior still unknown.
A bounded conclusion might read: “In this run, after the optional-purpose choice, a request to metrics.example included the full article URL and v-204. The endpoint returned a response. The capture does not establish retention duration or subsequent sharing.” That is more useful than either “the site tracks everything” or “only anonymous analytics were collected.”
Exported traces are data disclosures too
A HAR file can contain URLs, identifiers, request bodies, cookies, and credentials. DevTools offers sanitized export that removes certain sensitive headers, but application-specific identifiers in URLs or bodies can survive it. Inspect and redact the artifact before sharing it. Preserve consistent replacements, such as A17 and B92, when the relationship between values is the point of the investigation.
We do not replay a captured purchase, billing, or other state-changing request merely to test whether it works. Inspection is sufficient for this exercise. Keep original sensitive evidence under appropriate access controls and share only what the explanation requires.
The packet should distinguish directly observed events from inferred meanings. A parameter named uid might be an identifier, but its scope still needs evidence. A consent field might be present, but its validity needs decoding against the applicable specification. A request called impression might report an event without proving rendering or viewability. Names are leads to investigate, not definitions to trust.
Finally, record what the packet cannot settle: server-side fan-out, hidden account joins, actual retention, deletion propagation, and unobserved later events. Public disclosures and authorized service records may help, but a browser-only audit should keep that boundary visible.
9. Follow the Copy, Then Ask What Control Remains
Priya’s visible experience was a page and an ad. Our investigation separated that experience into requests, storage operations, namespace translations, and possible inferences. Those mechanisms explain why the privacy question cannot be reduced to whether a third-party cookie appeared.
There are also concrete engineering choices at each step. A publisher can send a content category instead of a full sensitive URL where that is sufficient, avoid unnecessary persistent identifiers, constrain which scripts execute in the page, and make optional collection wait for the appropriate state. A receiving service can limit retention and onward sharing, restrict joins, and preserve evidence of its processing rules. These choices determine how much exposure the architecture creates.
Browser controls can affect requests, storage, and linkage opportunities; what servers already retained, and whether downstream contracts are honored, lie outside their reach. The data ledger continues after the page closes, and an event may even be queued for transmission as visibility changes; APIs such as sendBeacon() support that pattern, subject to delivery limitations.
The central discipline is to keep four things separate: what was sent, who received it, what could be inferred, and what was actually done with it. A responsible account neither treats every possible inference as an observed fact nor treats missing evidence as proof of privacy.
In the next article, we move from this browser-level evidence to the wider systems that connect it: what replaces the stable cross-site identifier, which identity mechanisms survive the browser changes described here, and how the errors in linkage we just saw shape the choices that follow.
Resources
- MDN, Referrer-Policy: what the browser-generated referrer carries (section 3).
- MDN, cookie guide, Web Storage API, and same-origin policy: cookie attachment, storage scope, and cross-origin access (section 4).
- MDN, state partitioning: how embedded state is separated by top-level site (section 4).
- Google, cookie-matching guide: a concrete identifier-matching integration (section 5).
- MDN, fingerprinting: recognition by combining browser characteristics (section 6).
- IAB Tech Lab, Global Privacy Platform: the GPP specifications for privacy signals (section 7).
- Chrome for Developers, Network panel reference: recording, inspecting, and exporting requests (section 8).
- MDN,
sendBeacon(): queued transmission as a page closes (section 9).