What investigating 10 website-tracking allegations taught us about Chrome DevTools, request timing, browser state, and the limits of automated privacy scanners.
Most developers have opened Chrome DevTools to investigate a failed API request, troubleshoot JavaScript, or check network performance.
But what happens when those same network requests become the subject of a legal allegation?
A Google Analytics request that fires on page load might seem completely ordinary during development.
A Meta Pixel request containing browser identifiers might be something you've seen hundreds of times.
Now imagine an attorney asks your engineering team:
"Can you establish exactly what our website transmitted, when it happened, and whether the allegations in this demand letter are technically accurate?"
Suddenly, viewing the Network tab isn't enough.
You need reproducible testing conditions, properly preserved evidence, a clear understanding of the browser's limitations, and a reliable way to connect observations to findings.
We encountered this challenge during a recent investigation at Auditzo involving 10 website-tracking allegations associated with a California Invasion of Privacy Act (CIPA) demand matter.
The investigation produced 81 hashed technical evidence artifacts across two formal browser sessions.
But the most interesting part wasn't the artifact count.
It was learning how easily a technically valid observation can turn into an unsupported conclusion if we aren't careful.
Let's walk through the engineering lessons.
1. Detecting a Tracking Script Is Not the Same as Observing Its Behavior
Suppose a website includes:
<script src="https://tracker.example/analytics.js"></script>
The domain above is fictional and used only for illustration.
A scanner can detect the script.
But that doesn't tell us whether it executed successfully, which network requests followed, what data was included, or what conditions triggered those requests.
For a useful technical investigation, we need to distinguish several things:
- Script presence: Is the script included in the page?
- Script execution: Did it execute during the tested session?
- Network transmission: What requests did the browser attempt, and what responses were observed?
- Request timing: When did those requests occur relative to navigation and user interaction?
- Browser state: What cookies, storage values, and consent-related conditions existed?
- Evidence limitations: What cannot be established from the browser alone?
A website might load a tracking library without immediately sending an analytics request.
Another website might send tracking requests through a first-party endpoint, server-side tagging setup, or another mechanism that a simple third-party script inventory misses.
This is why technology detection is a useful starting point, not a complete behavioral assessment.
2. Start With a Reproducible Browser Session
Before investigating any particular tracking allegation, establish a controlled baseline.
For a public website, a practical starting configuration might include:
- A clean browser profile without existing site cookies or local storage.
- A documented browser version, operating system, and test location.
- Chrome DevTools opened before navigation.
- Network recording enabled with Preserve log selected.
- A fresh page navigation without clicking, scrolling, or submitting forms.
- Screenshots capturing the initial visible state.
- A record of when intentional user interactions begin.
Document any cache, service-worker, extension, privacy-setting, or network conditions that might influence the result.
Avoid treating an incognito window as a complete substitute for a documented clean environment.
Why testing conditions matter
Imagine two testers examining the same website.
Tester A has previously accepted tracking cookies.
Tester B is visiting with a fresh browser profile.
Their network activity may differ.
Geographic location, browser settings, existing storage, feature flags, and application state may also affect the requests generated.
If the environment isn't documented, a later reviewer may struggle to reproduce or interpret the original finding.
In our Auditzo engagement, the public-site investigation included a fresh, no-interaction browser session covering the homepage and four representative pages.
We separately examined an authorized customer-portal session.
Keeping these journeys distinct was important because authenticated browser behavior introduces different session and data-handling considerations.
3. Investigate Request Timing, Not Just Request Presence
One of the significant observations in the investigation involved analytics and advertising requests occurring before intentional user interaction.
During the fresh homepage baseline, five request families referenced in the complaint materials appeared approximately 6.2 to 10.6 seconds after the initial document request.
The tester had not intentionally clicked, scrolled, or submitted a form.
No visible consent-management interface appeared before those requests.
Here's the distinction engineers should pay attention to:
We observed the request timing. We did not establish the visitor's legal consent status or determine whether a statute had been violated.
Those are different propositions.
Inspecting the timeline in Chrome DevTools
Open DevTools and navigate to the Network tab.
For relevant requests, inspect:
- The complete request URL and destination.
- HTTP method and response status.
- Start time relative to the document request.
- Initiator information, where available.
- Query parameters and request payload.
- Request and response headers.
- Related cookies and browser storage.
Use the Initiator and Timing views to understand the available execution and network context.
Be careful with the interpretation of timing fields.
HAR startedDateTime values describe when individual network entries began. They are not automatically timestamps of a user's consent action.
Similarly, HAR timing fields such as wait, connect, and receive describe phases of request processing, not how long the visitor waited before interacting.
For a reliable observation, relate network timestamps to explicitly documented navigation and interaction checkpoints.
4. A Small Python Script for Inspecting HAR Request Timing
HAR files are JSON documents, which makes them convenient for automated inspection.
Here's a small Python example that extracts the first observed request for selected hosts and calculates its start-time offset from a chosen document request.
import json
from datetime import datetime
from urllib.parse import urlsplit
HAR_FILE = "baseline.har"
# Replace with the actual document URL recorded in HAR.
DOCUMENT_URL = "https://example.com/"
# Fictional hosts for demonstration.
TRACKER_HOSTS = {
"metrics.example",
"ads.example",
}
def parse_time(value):
return datetime.fromisoformat(
value.replace("Z", "+00:00")
)
with open(HAR_FILE, "r", encoding="utf-8") as file:
har = json.load(file)
entries = har["log"]["entries"]
# Find the documented baseline request.
document = next(
(
entry
for entry in entries
if entry["request"]["url"] == DOCUMENT_URL
and entry["request"]["method"] == "GET"
),
None
)
if document is None:
raise ValueError(
"Document request not found in HAR"
)
baseline = parse_time(
document["startedDateTime"]
)
first_seen = {}
for entry in entries:
url = entry["request"]["url"]
host = urlsplit(url).hostname or ""
if host not in TRACKER_HOSTS:
continue
started = parse_time(
entry["startedDateTime"]
)
offset = (
started - baseline
).total_seconds()
if host not in first_seen:
first_seen[host] = offset
else:
first_seen[host] = min(
first_seen[host],
offset
)
for host, offset in sorted(
first_seen.items(),
key=lambda item: item[1]
):
print(
f"{host}: first request at "
f"{offset:.3f}s"
)
Example output using fictional data:
metrics.example: first request at 2.318s
ads.example: first request at 5.742s
This is a basic inspection utility, not a forensic assessment tool.
It groups requests by hostname, which isn't necessarily equivalent to a tracking request family. A production investigation may need to distinguish specific paths, endpoints, payload types, redirects, and first-party proxy endpoints.
It also doesn't establish that a user consented, that a vendor stored information, or that the browser captured every possible transmission.
And if the initial navigation involved redirects, you'll need to identify the correct baseline entry rather than assuming that the first document URL is always the final page URL.
Nevertheless, programmatic timeline extraction is useful for narrowing down requests that deserve manual inspection.
5. Understand What HAR Files Cannot Prove
This was one of the most important engineering lessons from our investigation.
A HAR capture can provide valuable information about browser-visible HTTP activity.
Depending on the capture and export settings, it may include request URLs, query parameters, headers, bodies, response details, and timing.
But there are boundaries.
Example: What source IP did a vendor actually log?
Suppose a browser sends a request to an external analytics endpoint.
Can the HAR file establish the exact source IP address recorded by the recipient?
Not independently.
A browser capture doesn't reveal every network intermediary or the remote service's internal logging and retention behavior.
The external service may observe an address influenced by NAT, a VPN, a proxy, or another part of the network path.
To establish what a remote vendor actually received or stored, additional evidence may be required.
Example: Does a persistent identifier establish a person's identity?
During our investigation, certain browser-level analytics and advertising identifiers remained stable across page navigation.
That supported an observation about cross-page browser correlation in the tested session.
It did not independently establish the identity of an individual visitor.
Nor did it demonstrate how a vendor subsequently profiled, enriched, or retained the information.
Example: What if a request contains authenticated route context?
During authorized portal testing, some third-party requests included authenticated page or route context.
That was worth documenting.
However, the available evidence did not show that individual training records, certificates, or test-result contents were transmitted.
Inferring that sensitive record contents were disclosed simply because a request occurred within an authenticated portal would have overstated the evidence.
As developers, we need to separate what the capture shows from what we think the surrounding infrastructure might be doing.
6. Protect HAR Files Before Sharing Them
One easily overlooked issue is that network evidence itself can contain sensitive information.
HAR files may include:
- Session cookies and authorization headers.
- Access tokens embedded in URLs.
- Form submissions and request bodies.
- Personal information in query parameters.
- Authenticated page context.
- Sensitive response data.
Chrome currently supports sanitized HAR exports by default, with separate options for exporting sensitive data when explicitly enabled.
However, a sanitized export should not be assumed to remove every possible secret or personal identifier. https://developer.chrome.com/docs/devtools/network/reference/
For technical investigations, use a controlled evidence-handling process:
- Capture only authorized, necessary activity.
- Store sensitive raw evidence in an appropriately restricted location.
- Create a separate reviewed or redacted copy for wider sharing.
- Preserve the relationship between the original and derived artifacts.
- Avoid uploading raw HAR files to public debugging tools or repositories.
For authenticated workflows, consider using dedicated test accounts and synthetic data whenever possible.
In our engagement, credential-bearing authentication evidence was kept restricted instead of being embedded directly in ordinary report material.
This separation matters for both security and evidence integrity.
7. Use SHA-256 Hashes to Track Evidence Artifacts
Our investigation produced 81 hashed evidence artifacts:
- 57 raw or restricted-raw artifacts.
- 24 human-verified derived artifacts.
One simple way to compute a SHA-256 hash in Python is:
from pathlib import Path
import hashlib
def sha256_file(filename):
digest = hashlib.sha256()
with open(filename, "rb") as file:
for chunk in iter(
lambda: file.read(1024 * 1024),
b""
):
digest.update(chunk)
return digest.hexdigest()
print(sha256_file("baseline.har"))
The hash helps identify the exact file bytes and detect subsequent changes.
If the file changes, its hash will generally change.
That can be useful when connecting an analysis report to the specific capture that supported it.
A simple manifest might look like this:
{
"capture_id": "PUBLIC-BASELINE-01",
"browser_state": "fresh",
"interaction": "none",
"artifacts": [
{
"file": "baseline.har",
"sha256": "<computed-file-hash>"
},
{
"file": "initial-state.png",
"sha256": "<computed-file-hash>"
}
]
}
This is an illustrative structure, not an extract from the client's evidence manifest.
Hashing is not a substitute for proper collection records, access controls, timestamps, or documented handling procedures.
It also does not automatically make evidence legally admissible.
But it provides a straightforward integrity check that is easy to integrate into an engineering workflow.
8. Create a Test Matrix Instead of Relying on One Browser Run
A single scan only describes the conditions under which that scan was performed.
For websites with consent-management systems, I'd recommend designing separate, controlled test cases.
| Test scenario | What to inspect |
|---|---|
| Fresh visit, no interaction | Initial requests, storage changes, visible consent UI |
| Consent accepted | Newly initiated requests and storage changes |
| Consent rejected | Requests and identifiers after rejection |
| Page navigation | Identifier persistence and additional request families |
| GPC enabled | Changes in browser-visible behavior under the signal |
| Authenticated session | Third-party requests and sensitive route or parameter exposure |
Not every scenario will apply to every website, and not every website exposes the same consent controls.
These are recommended test scenarios, not a claim that all of them were executed in the Auditzo case discussed here.
The key is to treat each scenario as a separate observation, with its own browser state and evidence.
Don't reuse a browser session across supposedly independent test conditions unless that continuity is intentional and documented.
And don't assume that a visible Reject All button proves that all tracking behavior is suppressed. Verify the actual technical behavior.
9. Turn Technical Observations Into Findings Someone Else Can Review
At the end of our CIPA investigation, the 10 technical assertions were classified as follows:
| Technical assessment | Count |
|---|---|
| Reproduced in current testing | 3 |
| Partially reproduced | 2 |
| Unable to determine | 3 |
| Historical evidence required | 2 |
| Not reproduced | 0 |
These were technical assessments, not judgments about legal merit.
This approach is useful beyond legal investigations.
A good engineering finding should explain:
What was tested?
The particular page, browser state, and scenario.
What was observed?
A specific network event, timing sequence, storage change, or application behavior.
Which evidence supports it?
The relevant capture, screenshot, manifest reference, or reviewed analysis.
What remains uncertain?
Historical behavior, server-side processing, vendor retention, or conditions that weren't tested.
Can another engineer reproduce it?
The investigation should provide sufficient context for another qualified reviewer to understand and, where feasible, repeat the test.
This is more useful than a report containing 50 warnings without clear reproduction conditions.
10. Technical Investigations Should Lead to Engineering Decisions
The same engagement later expanded into a separate WCAG 2.2 accessibility assessment.
That review identified 19 consolidated verified findings, including keyboard-navigation difficulties, informative images with missing alternative text, insufficient contrast, and responsive reflow issues.
Our engineering team subsequently implemented the agreed production improvements.
The accessibility review was a separate workstream, but it reinforced the same engineering principle.
A finding becomes more useful when it can be connected to a specific behavior, user impact, and remediation action.
The investigation must remain honest about its verification scope. Implementing changes doesn't, by itself, prove complete accessibility conformance or establish that all possible tracking issues have been resolved.
Final Thoughts: Debugging Is Not the Same as Proving
As developers, we're trained to identify problems and fix them.
But privacy-related technical investigations add another responsibility: explaining exactly what the available evidence does and does not establish.
A tracking request may have occurred.
Its timing may be measurable.
Its visible parameters may be documented.
But that doesn't automatically tell us what happened in an earlier browser session, what a remote vendor retained, or whether a particular legal allegation is valid.
The biggest lesson from this engagement wasn't about using a more advanced scanner.
It was about using familiar engineering tools with greater discipline.
Capture the behavior. Document the conditions. Preserve the evidence. State the limitations. Then make decisions based on what can actually be established.
That's a much stronger engineering practice than treating every detected third-party request as a confirmed violation or every clean scan as proof of safety.
Further Reading
The investigation described here was part of a real Auditzo engagement involving technical evidence for counsel, followed by a separate accessibility assessment and production remediation.
For the full investigation methodology, findings, and scope limitations:
Read the Auditzo CIPA Website Tracking Evidence Case Study
Useful technical references:
This article is intended for developers and technical professionals. The code examples are illustrative, not a representation of the original client's investigation scripts. The observations described are technical findings, not legal determinations.
Top comments (0)