Whether a request left your site before a visitor made any consent choice is not an argument. It is something you can check in the next ten minutes, with tools already installed on your computer, without buying anything or reading a page of case law. This is that check: how to run it by hand, what it looks like when something is wrong, and where the manual version of it quietly fails you.
None of what follows tells you whether a given request is a legal problem. It tells you what left your browser and when, which is the fact any legal argument about it would eventually have to be built on top of, one way or another.
What "pre-consent" means, precisely
Pre-consent is a window, not a feeling. It starts at navigation start, the moment the browser begins loading the page, and it ends at the visitor's first interaction with your consent interface, whichever specific control that turns out to be: a click on "Accept," a click on "Reject," a toggle, or a close button. Anything that leaves your browser before that first click happened inside a window where no choice had been made yet, no matter how quickly it happened. A banner that renders in 900 milliseconds does not shrink the window; it only compresses how much time a request has to leave before anyone could have reacted to it.
That definition is worth being precise about because it is checkable. It does not depend on what the banner's copy says its defaults are, what a settings screen reports as blocked, or what a privacy policy claims about vendor behavior. It depends on what left the browser, and when, relative to one specific, observable moment: the click. Everything below is about capturing that moment and everything that happened before it.
The walkthrough: check it yourself
This works in any Chromium-based browser (Chrome, Edge, Brave) or Firefox. The panel names differ slightly across browsers; the steps do not.
- Start clean. Open a fresh browser profile, or at minimum a new private or incognito window with no extensions running. A leftover consent cookie from an earlier visit can suppress the banner entirely, and an ad blocker can suppress the exact requests you are trying to observe. Either one quietly invalidates the test before it starts.
- Open DevTools before you load the page. Switch to the Network tab, enable "Preserve log" so a redirect does not clear your capture, and clear any existing entries. Then load the URL. If the panel is opened after the page has already started loading, the beginning of the window is already gone; reload with the panel open instead of trying to open the panel after the fact.
- Do not touch the banner yet. Let the page sit for a few seconds. Everything visible in the panel right now happened before you made any choice, which is the entire point of the exercise.
- Separate your own traffic from everyone else's. The Network tab's Domain column, or a filter such as
-domain:yoursite.comwith your own hostname substituted in, isolates requests going to a third party. Anything that is not your domain and is not a CDN you deliberately chose is worth a second look. - Record what is there before you click anything. For each third-party request: the domain, the request method, and its time relative to navigation start, which the Network tab's Time or Waterfall column already gives you.
- Only then interact with the banner. Click "Reject All" or its equivalent, and see whether the same domains keep appearing afterward. A domain that only shows up after you accept is a different, and less interesting, finding than one that already fired before you touched anything.
The Network tab gives you all of this by hand, but reading it row by row is slow. The browser's own performance API can pull the same list programmatically. Paste this into the console right after the page loads, before you touch the banner:
performance.getEntriesByType('resource')
.filter(r => !r.name.startsWith(location.origin))
.map(r => ({ url: r.name, startedAtMs: Math.round(r.startTime) }));performance.getEntriesByType('resource') returns every resource the page has loaded since navigation started, in order, with a start time you can compare against when the banner actually rendered. Filtering out your own origin leaves the third-party calls, which is the list the Network tab walk above builds by hand.
What a failure looks like
A failure is not a dramatic-looking request. It is an ordinary one that arrived too early. Here is a representative console output from the snippet above, captured on a page where the consent banner did not finish rendering until roughly 1,500 milliseconds after navigation, and the visitor's first click on it did not happen until around 4,200 milliseconds:
[
{ url: "https://sync.ad-exchange.example/pixel?vid=88f21a0c&cid=5521", startedAtMs: 612 },
{ url: "https://collect.session-tool.example/rec?sid=9c3e77b1", startedAtMs: 940 }
]Both requests completed before the banner had even finished rendering, let alone before the visitor had a chance to react to it. The first request's query string carries a visitor identifier and a campaign identifier, the shape an ad-exchange sync call ordinarily takes. The second carries a session identifier, the shape a session-replay recorder's opening beacon ordinarily takes. Neither request needed the banner to exist, and neither one waited for it.
What makes this a failure worth acting on is not the domain names, which are illustrative here. It is the relationship between the two numbers: the request's startedAtMs and the moment the visitor could first have made a choice. A request that fires at 600 milliseconds on a page where the banner does not even render until 1,500 milliseconds could not possibly have been waiting on a decision that had not yet become available to make.
Where the manual version misses things
A single capture, taken once, from one browser, tells you the truth about one page load. It does not generalize as far as it feels like it should. Four gaps are worth knowing about before you treat a clean result as reassurance.
- Geography-gated banners. Many consent interfaces render differently, or not at all, depending on the visitor's inferred location. Testing from outside California, through a VPN, or from a cloud provider's IP range may show you a different interface, or none, than the one a California visitor actually sees. A clean capture from your own desk does not necessarily describe the experience of the visitor whose consent choice is the one that matters.
- Tags that only fire on some routes. A pixel added to a checkout flow, a landing page built outside your main template, or a single campaign page never touches the homepage a quick check usually covers. A capture of your homepage is a finding about your homepage.
- Vendor updates that add a piggybacked request. A script that behaved correctly the last time you looked can start making an additional request to a fourth party in a later release, with nothing changing on your end at all. The capture you took describes the vendor's behavior on the day you took it, not on the day someone reads your notes about it.
- Server-side forwarding a browser panel never sees. Conversion APIs and server-to-server forwarding run on your own infrastructure, after the fact, entirely outside the browser. No amount of watching the Network tab shows you a call your own server makes to an advertising platform after receiving a pageview, because that call never reaches the visitor's browser in the first place.
What to keep as evidence
A clean or dirty read of the Network tab does not survive being described from memory later. What holds up, whether you are handing it to a vendor, to your own engineering team, or to whoever asked you to check, is the record itself: the domain, the timing relative to navigation and to the first click, and, in your own browser's capture, the full request URL. Two things are worth doing before you close the tab.
- Export the capture as a HAR file. Right-click anywhere in the Network panel's request list and export as HAR; the exact wording of the menu item differs slightly between browsers. A HAR file preserves every request, its timing, and its full URL in a format you can hand to someone else or reopen months later, rather than a paraphrase of what you remember seeing.
- Note the interaction timestamp alongside it. The request timing means nothing without a reference point. Write down, even roughly, when the banner rendered and when you clicked it, next to the exported file, so a reader can tell which requests preceded the click and by how much.
A screenshot of a consent platform's dashboard is not a substitute for either of these. It shows a configuration, not a runtime event, and the two do not always describe the same page. We have written before about the specific gap between a consent platform's configured categories and what actually reaches the page, including why a loader can only enforce the scripts it was pointed at, and about the concrete, vendor-by-vendor patterns that gap tends to produce in a closer look at where hidden trackers commonly turn up. This page is the mechanics of finding it yourself, on your own site, before you go looking at either.
Why the timing question sits inside the CCPA too
Two parts of the CCPA regulations describe why this specific window matters, apart from any other litigation exposure a third party's request might carry. Section 7012 requires that a Notice at Collection reach the consumer at or before the point personal information is collected; a request that has already reached a third-party endpoint before your notice or consent interface has even rendered is a request that arrived before that notice had a chance to do its job. Section 7004 governs the design of the mechanism used to obtain consent, including that the resulting choice architecture must not impair a consumer's ability to decide; a page where collection is already underway before the choice screen has finished loading is a timing problem in exactly the area section 7004 is concerned with.
Neither section turns any single finding into a violation on its own, and that determination is not one a page load can make. What they establish is that the question this page walks through, what left your site and when relative to a visitor's choice, is not a CIPA-only curiosity. It sits inside the CCPA's own regulatory text as well.
Run this check without opening a console
Our free CCPA checker loads your URL once and runs the walkthrough above automatically. You get the trackers that fired before your consent interface's first interaction, the domain each one contacted, and the timing relative to that interaction, as a timestamped list you can keep.
Get your timestamped list