DEV Community

Cover image for Received a CIPA Demand Letter? Debug the Browser Before You Change the Code
Auditzo
Auditzo

Posted on Originally published at auditzo.com

Received a CIPA Demand Letter? Debug the Browser Before You Change the Code

A developer-focused workflow for preserving website tracking evidence, comparing consent states, inspecting HAR/network traffic, and separating detection from actual browser behavior.

When a company receives a demand letter involving website tracking, the engineering instinct is usually immediate:

Remove the pixel. Disable the script. Change the consent configuration. Ship the fix.

That instinct is understandable.

But from a technical evidence perspective, changing the implementation too quickly can create another problem:

You may destroy the browser state you still need to understand.

If the allegation involves a tracking pixel, analytics library, session-replay tool, chatbot, tag manager, or another third-party integration, the useful engineering question is not simply:

Is this script installed?

The better question is:

What did the browser actually do during the relevant user journey, and what evidence supports that observation?

That distinction changes how I approach website-tracking investigations.

This article walks through the problem from a developer and technical-evidence perspective.

It is not legal advice, and it does not determine whether any particular website violates the California Invasion of Privacy Act (CIPA).


The Core Model: Detection != Execution != Transmission

This is probably the most important technical distinction in the entire workflow.

A scanner might tell you:

  • Meta Pixel detected
  • Google Analytics detected
  • Session replay detected
  • Chat widget detected

Useful?

Absolutely.

Enough to describe what actually happened during a browser session?

No.

I prefer to separate the investigation into five layers:

Detection -> Execution -> Network Behavior -> Technical Interpretation -> Legal Interpretation

Each layer answers a different question.

Detection

Is the script, tag, SDK, endpoint, iframe, library, or third-party integration present?

Detection may come from:

  • page source
  • DOM inspection
  • script inventories
  • Tag Manager inspection
  • automated scanners
  • browser extensions
  • static analysis

Detection gives us an inventory.

It does not give us the complete runtime story.

Execution

Did the detected technology actually execute during the session being tested?

A script may exist on the website without firing during every visit.

A tag may execute only after:

  • consent
  • authentication
  • navigation
  • a form interaction
  • a checkout event
  • a SPA route change
  • a custom JavaScript event
  • another application condition

This is why runtime evidence matters.

Network Behavior

If the technology executed, did it cause observable requests to leave the browser?

If yes:

  • Which domain received the request?
  • When did the request occur?
  • What initiated it?
  • Was it GET, POST, fetch, XHR, beacon, image, or iframe traffic?
  • What query parameters were present?
  • Which headers were observable?
  • Was there a request body?
  • Were identifiers or other values observable?
  • What consent state existed at the time?

This is where the investigation becomes substantially more useful.

Technical Interpretation

What does the captured browser evidence actually demonstrate?

And equally important:

What does it not demonstrate?

A good technical finding should include both.

Legal Interpretation

What legal significance does that behavior have under CIPA or another law?

That is a different question.

Developers, scanners, and technical auditors can establish observable technical behavior.

Counsel determines what that behavior means legally.

Keeping those responsibilities separate makes the technical evidence much stronger.


Start With the Allegation, Not With the Scanner

If somebody gives an engineering team a website-tracking allegation, the natural first move may be:

Run every scanner we have.

I would not start there.

A broad scan is useful later for discovery.

First, translate the allegation into technical assertions.

Suppose the allegation effectively says:

A third-party technology collected or transmitted information when a user visited a particular page before providing consent.

Now turn that into questions a developer can actually test:

  1. Which page is involved?
  2. Which third-party technology is identified?
  3. What constitutes a clean first visit?
  4. What happens before any consent interaction?
  5. Does the relevant code execute?
  6. Does a third-party request occur?
  7. Which endpoint receives it?
  8. What is actually observable in the request?
  9. Can the behavior be reproduced?
  10. Which artifact supports each observation?

Now you have a technical test plan.

That is very different from:

Run scanner -> export tracker list -> write conclusion.


Preserve the Current State Before Changing It

Imagine engineering receives this ticket:

URGENT: Disable tracking pixel because of privacy demand.

Before changing production, someone should ask:

Do we need to preserve the current technical state first?

That does not mean necessary security, privacy, operational, contractual, or legally directed remediation should be delayed.

It means preservation should be considered deliberately rather than skipped accidentally.

A useful evidence package might contain:

session/
├── context.json
├── network.har
├── cookies.json
├── storage.json
├── console.json
├── screenshots/
│   ├── initial.png
│   ├── accept.png
│   └── reject.png
├── observations.json
└── manifest.json
Enter fullscreen mode Exit fullscreen mode

The exact folder structure is not the important part.

Traceability is.

For each test session, I want to know:

  • Which URL was tested?
  • What date and time?
  • Which time zone?
  • Which browser and version?
  • Which viewport?
  • Was this a clean browser context?
  • Was the user authenticated?
  • What consent state existed?
  • Which actions were performed?
  • Which artifact belongs to this session?

Without that context, a folder full of screenshots and HAR files becomes surprisingly difficult to interpret later.


Treat Consent as a State Machine

One of the most common mistakes in website privacy testing is treating consent as this question:

Does the site have a cookie banner?

Yes or no.

From an engineering perspective, that tells us almost nothing about runtime behavior.

I prefer to model at least three distinct states:

INITIAL

ACCEPT

REJECT

Each should be tested separately.

Initial State

Start with a clean browser context.

No previously stored consent decision.

Now observe:

  • Which scripts execute?
  • Which third-party requests occur?
  • Which cookies appear?
  • What enters localStorage?
  • What enters sessionStorage?
  • Does anything fire before the visitor touches the consent interface?

Accept State

Run another controlled session and accept tracking.

Then ask:

  • Which additional scripts execute?
  • Which new requests appear?
  • Which third parties receive them?
  • Which cookies are created?
  • Does browser storage change?
  • Which behavior exists only after acceptance?

Reject State

Run another clean session and reject non-essential tracking.

Then ask:

  • Which requests stop?
  • Which requests continue?
  • Which cookies remain?
  • Do marketing scripts still execute?
  • Does behavior differ from Initial?
  • Is the rejection persisted after reload?

Now compare the states.

Conceptually:

Initial network set = I
Accept network set  = A
Reject network set  = R

New after acceptance = A - I
Still active after rejection = R
Observed before a choice = I
Enter fullscreen mode Exit fullscreen mode

This comparison usually tells you much more than looking at the consent banner itself.


Use Clean Browser Contexts

Testing privacy behavior in your everyday Chrome profile is a bad idea.

Your normal browser may already contain:

  • consent cookies
  • authentication state
  • localStorage
  • sessionStorage
  • cached resources
  • service workers
  • previously assigned identifiers
  • browser extensions
  • stale application state

For reproducible testing, isolate the session.

With Playwright, the basic idea is simple:

const context = await browser.newContext();
const page = await context.newPage();
Enter fullscreen mode Exit fullscreen mode

For stronger repeatability, document the environment as well.

For example:

Browser: Chromium
Locale: en-US
Timezone: America/Los_Angeles
Viewport: 1440x900
Authenticated: false
Prior cookies: none
Prior localStorage: none
Prior consent state: none
Enter fullscreen mode Exit fullscreen mode

Playwright is only one option.

Selenium, Puppeteer, browser DevTools, or another controlled testing environment can work.

The important principle is:

Control the environment before interpreting the evidence.


HAR Files Are Powerful, but They Need Context

HAR files can be extremely useful in website-tracking investigations because they preserve network activity.

Depending on how they are captured, they may help show:

  • request URLs
  • HTTP methods
  • timestamps
  • third-party destinations
  • query parameters
  • selected headers
  • request payload information
  • response details
  • ordering of network activity

That is significantly more informative than:

Meta Pixel detected.

But a HAR file is not self-explanatory.

Suppose we see:

GET https://tracker.example/collect?id=12345&event=pageview
Enter fullscreen mode Exit fullscreen mode

Useful?

Yes.

But we still need context.

  • Which page generated it?
  • Was this before or after consent?
  • Was this a clean browser session?
  • Did the user interact with anything?
  • Was the request produced by application code or a Tag Manager trigger?
  • Did the same request occur after Reject?
  • What values were actually observable?
  • Which values are being inferred rather than directly observed?

A HAR is an artifact.

The investigation connects that artifact to a reproducible browser observation.


Be Precise About What Was Actually Transmitted

Another common failure mode is moving too quickly from technology detection to assumptions about data transmission.

For example:

Technology X is installed

does not automatically establish:

Technology X transmitted information Y

Inspect the request.

If the captured evidence contains values such as:

event=page_view
page=/checkout
client_id=...
Enter fullscreen mode Exit fullscreen mode

those values can be documented as observable.

If an alleged value is not observable in the captured request, that should be stated too.

I like separating findings into three buckets:

Observed directly

Inferred

Not established by available evidence

Those are very different things.

A technical report becomes more credible when it is willing to say:

We did not establish this from the available evidence.


Reproduce the Actual User Journey

The homepage may not be the relevant page.

Tracking behavior may occur only after:

  • searching
  • viewing a product
  • adding an item to cart
  • beginning checkout
  • submitting a form
  • opening a chatbot
  • entering data
  • creating an account
  • navigating through a SPA route
  • triggering a custom application event

If an allegation describes a particular interaction, reproduce that interaction.

A controlled test might look like this:

Session: T-003
Consent state: Initial

1. Launch clean browser context
2. Navigate to homepage
3. Do not interact with consent manager
4. Navigate to /product/example
5. Click "Add to Cart"
6. Open /cart
7. Capture network activity
8. Capture cookies and browser storage
9. Capture screenshots
10. Close session
Enter fullscreen mode Exit fullscreen mode

Now run the same journey after Accept.

Then again after Reject.

You now have comparable sessions rather than an unstructured collection of browser observations.


Keep Discovery and Verification Separate

Automation is excellent for discovery.

A scanner may quickly report:

Third-party domains: 27
Cookies: 18
Known trackers: 7
CMP detected: yes
Network requests: 164
Enter fullscreen mode Exit fullscreen mode

That helps identify where deeper investigation may be needed.

But allegation verification asks a different question:

Did this specific behavior occur during this specific user interaction under this specific consent state?

That may require:

  • controlled browser sessions
  • browser automation
  • manual inspection
  • network capture
  • request-level analysis
  • reproducing the relevant workflow
  • evidence references
  • human technical interpretation

I think of the workflow like this:

Automation -> Discovery -> Investigation Target -> Controlled Reproduction -> Evidence Verification

Automation should reduce manual work.

It should not replace evidence reasoning.


A Tracker List Is Not an Evidence Record

A list like this:

  • Meta Pixel
  • Google Analytics
  • TikTok Pixel
  • Microsoft Clarity
  • Session replay
  • Chat widget

is useful for inventory.

But it does not explain what happened in a specific browser session.

A stronger technical record connects:

Finding

to

Session

to

Observed behavior

to

Supporting artifact

to

Limitations

That traceability matters more than simply producing a longer report.


Store Findings as Structured Evidence

Instead of treating a PDF as the only source of truth, findings can also be represented internally as structured records.

For example:

{
  "finding_id": "NET-004",
  "title": "Third-party request observed before consent choice",
  "session_id": "INITIAL-001",
  "page": "/example",
  "consent_state": "initial",
  "observed": true,
  "destination": "tracker.example",
  "evidence": [
    {
      "type": "har",
      "artifact": "initial.har",
      "reference": "request-84"
    },
    {
      "type": "screenshot",
      "artifact": "screenshots/initial-page.png"
    }
  ],
  "limitation": "Current-state observation only"
}
Enter fullscreen mode Exit fullscreen mode

Now the finding becomes traceable.

A reviewer can go from:

Finding -> Session -> Network Record -> Supporting Artifact -> Limitation

That is much closer to evidence engineering than merely generating another large PDF.


Hash Artifacts When Integrity Matters

If technical artifacts need to remain stable over time, integrity metadata can help.

For example:

network.har

SHA-256:
4fb6...example...91ae
Enter fullscreen mode Exit fullscreen mode

A simple manifest might look like:

{
  "files": [
    {
      "path": "network.har",
      "sha256": "...",
      "size": 381249
    },
    {
      "path": "cookies.json",
      "sha256": "...",
      "size": 7402
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Hashing does not magically make evidence legally admissible.

It does not prove that a legal requirement has been satisfied.

It simply provides a technical mechanism for checking whether a preserved artifact remains byte-for-byte identical to the recorded version.

That is a useful technical property.

Nothing more should be claimed from it.


Be Careful With Sensitive Data in HAR and Browser Storage

HAR files can contain more than developers initially expect.

Depending on the application, they may include:

  • authentication headers
  • session tokens
  • cookies
  • user identifiers
  • email addresses
  • form values
  • query parameters
  • internal API endpoints
  • account-specific data

The same applies to cookies and browser-storage exports.

Do not casually attach raw evidence to:

  • Jira tickets
  • Slack channels
  • shared drives
  • email chains
  • public bug reports

A better model can separate:

Original restricted artifact

from

Sanitized working artifact

For example:

raw/network.har
working/network.sanitized.har
Enter fullscreen mode Exit fullscreen mode

The original remains access-controlled.

The sanitized copy can be used where full raw data is unnecessary.


Current-State Testing Cannot Automatically Reconstruct History

This limitation is critical.

Suppose an allegation concerns website behavior from three months ago.

You test the website today and find:

Pixel does not fire before consent.

Can you conclude:

It did not fire before consent three months ago.

No.

The implementation may have changed.

Potential changes include:

  • Git deployments
  • Tag Manager publications
  • CMP configuration changes
  • vendor library updates
  • feature flags
  • marketing configuration
  • CDN changes
  • server-side tagging
  • application logic
  • consent defaults

Current testing establishes what can be observed now.

It does not automatically reconstruct an earlier website state.

If historical technical material is available, keep it separate.

I prefer this distinction:

Historical supplied evidence

versus

Current independently reproduced evidence

Never silently merge them into one timeline.


Preserve Version Context Where Possible

Engineering teams may have historical records that become useful later.

Potential sources include:

  • Git history
  • deployment logs
  • Tag Manager version history
  • CMP configuration history
  • CDN configuration
  • release notes
  • archived builds
  • infrastructure logs
  • vendor configuration records
  • issue-tracker history

These records may help answer whether the current implementation differs from an earlier one.

But be careful with the inverse assumption.

The absence of a recorded change does not automatically prove that no change occurred.

Again:

Document what the evidence establishes, not what you wish it established.


Remediation Should Produce a New Evidence State

After preservation, the implementation may need to change.

That might mean:

  • updating tag firing rules
  • changing CMP configuration
  • disabling a third-party script
  • moving initialization behind consent
  • changing consent defaults
  • modifying Tag Manager triggers
  • removing a tracking pixel
  • changing browser-storage behavior
  • updating a chatbot integration

After deployment, do not overwrite the previous test.

Create a second evidence state.

For example:

BEFORE/
├── initial.har
├── accept.har
├── reject.har
└── manifest.json

AFTER/
├── initial.har
├── accept.har
├── reject.har
└── manifest.json
Enter fullscreen mode Exit fullscreen mode

Now you can compare:

Original observed state

with

Post-remediation observed state

That is significantly more useful than closing the ticket with:

Pixel fixed.


Verify the Fix at the Network Layer

A code change does not automatically prove a runtime change.

Suppose you modify the implementation to:

if (hasConsent) {
  loadAnalytics();
}
Enter fullscreen mode Exit fullscreen mode

Good.

Now test it.

Check:

  • Fresh visit with no consent
  • Accept
  • Reject
  • Reload after Reject
  • SPA navigation after Reject
  • Relevant conversion or user journey

Then compare:

  • network requests
  • cookies
  • browser storage
  • script execution
  • network destinations

The code is the implementation.

Runtime behavior is the evidence.


Do Not Turn Request Counts Into Legal Conclusions

Technical teams often see numbers such as:

42 network requests
8 third-party requests
3 tracking domains
12 cookies
5 page views
Enter fullscreen mode Exit fullscreen mode

Those are technical observations.

They should not automatically become:

42 legal violations
Enter fullscreen mode Exit fullscreen mode

or:

$X in exposure
Enter fullscreen mode Exit fullscreen mode

CIPA contains statutory remedies that are frequently discussed in website-tracking disputes, but deciding whether conduct constitutes a violation, how alleged violations may be counted, what defenses exist, and what damages may be available are legal questions.

The technical team's responsibility is different:

Establish accurate underlying evidence.

Then counsel can interpret it.


Pen Register and Trap-and-Trace Terminology Needs the Same Discipline

CIPA's pen-register and trap-and-trace provisions use statutory terminology involving routing, addressing, dialing, or signaling information.

From an engineering perspective, the safe approach is not to label every tracker:

Pen register.

Instead document objectively:

Technology detected: X
Executed: yes/no
Request observed: yes/no
Destination: X
Timing: X
Consent state: X
Observable request fields: X
Triggered by: X
Supporting artifact: X
Enter fullscreen mode Exit fullscreen mode

Then counsel can evaluate whether and how the legal terminology applies.

The technical record remains useful regardless of the ultimate legal characterization.


Pending Legislation Is Another Reason to Separate Technical and Legal Layers

Privacy law and website-tracking litigation continue to evolve.

California SB 690, for example, has been part of the ongoing legislative discussion around CIPA website and application claims.

For developers, the important lesson is not to encode assumptions about pending legislation into technical findings.

Your evidence architecture should continue to answer:

  • What happened?
  • When did it happen?
  • Under which consent state?
  • What was observable?
  • Which artifact supports the finding?
  • What are the limitations?

Legal teams can apply the current statute, case law, and legislative developments to those facts.

Technical evidence structured this way ages much better.


My Practical Website-Tracking Investigation Checklist

If I were starting an investigation tomorrow, my engineering checklist would look roughly like this.

1. Understand the allegation

Identify:

  • technology
  • page
  • user interaction
  • alleged consent state
  • alleged destination
  • alleged information
  • relevant date
  • supplied evidence

2. Preserve supplied material

Keep originals separately.

Do not overwrite them.

3. Define the test environment

Document:

  • browser
  • version
  • viewport
  • timezone
  • authentication state
  • cache/storage state
  • consent state

4. Start with a clean browser session

Do not contaminate the result with previous state.

5. Capture Initial

Before any consent interaction.

6. Reproduce the relevant user journey

Do not limit the investigation to the homepage unless that is actually the relevant page.

7. Capture network evidence

HAR plus request-level inspection where appropriate.

8. Capture browser state

Cookies, localStorage, sessionStorage, screenshots, and relevant console observations.

9. Repeat after Accept

Use another controlled session.

10. Repeat after Reject

Again, independently.

11. Compare the states

Look for behavioral differences, not merely visual differences.

12. Build traceable findings

Every important observation should reference evidence.

13. Document limitations

Especially historical versus current-state limitations.

14. Preserve the original state

Do not replace it with the remediation test.

15. Remediate

Coordinate with the appropriate engineering, security, privacy, business, and legal teams.

16. Retest

Use fresh sessions after deployment.

17. Compare Before and After

Document what actually changed at runtime.


The Engineering Principle I Keep Coming Back To

For website-tracking investigations, I keep returning to one principle:

Do not infer browser behavior from the existence of code when you can measure the browser behavior itself.

A tracker being detected is useful information.

But:

Detection != Execution

Execution != Observable Network Transmission

Observable Network Transmission != Legal Interpretation

If the behavior matters enough to investigate:

  • make the session reproducible
  • preserve the environment
  • capture network activity
  • compare consent states
  • connect findings to artifacts
  • state limitations clearly
  • preserve the original state separately
  • verify the post-remediation state independently

That creates a much stronger technical record than either:

We found a tracker, therefore there is a violation.

or:

We removed the tracker, therefore the issue is resolved.

Neither statement tells us enough.


A Deeper CIPA Website-Tracking Evidence Guide

At Auditzo, we recently published a more detailed guide for attorneys, businesses, privacy teams, and technical teams dealing with CIPA website-tracking demand letters.

It covers:

  • evidence preservation before website changes
  • allegation-specific testing
  • Initial, Accept, and Reject consent-state comparison
  • HAR and network evidence
  • cookies and browser storage
  • historical versus current-state evidence
  • automated discovery versus manual verification
  • traceable technical findings
  • remediation
  • post-remediation verification

Read the full guide:

https://www.auditzo.com/guides/cipa-demand-letter-website-tracking-evidence

Auditzo focuses on observable website behavior and technical evidence for business, privacy, and counsel review.

We do not provide legal advice, determine whether a CIPA violation has occurred, or provide legal compliance certification.

If you work in privacy engineering, browser automation, consent management, tag management, or network debugging, I would be interested in hearing how you structure reproducible technical evidence when website behavior may later need to be explained outside the engineering team.

Top comments (0)