Faraday

Sealed-browser consent audit · closed beta

Your banner says no. Prove it.

Faraday sends a made-up visitor through your site and has her reject tracking. Every tag runs for real inside a sealed browser. Nothing reaches a vendor. Then you see exactly which tags tried to collect her data anyway.

Runs before real traffic0 requests reach vendorsFails the build on a regression
Closed betaby invite
0 vendor hitsby design
✕ BLOCKED AdNet beacon before any consent choice → 204 ✕ BLOCKED card number to stats-cdn.test as base64 → 1×1 gif ✕ CAUGHT MetricsCo wrote _mx_id to localStorage without analytics consent ✕ BLOCKED card digits hex-encoded into a dns-prefetch hostname ✕ CAUGHT cdn-jslib.test reads the payment field "card" ✕ BLOCKED ad tag ignored Global Privacy Control → 204 ✕ CAUGHT visitor re-identified in a clean session after withdrawal ✕ CAUGHT ChatWidget opened a WebSocket without functional consent

One run, the demo shop

Everything fires. Nothing gets out.

From one full audit of the bundled demo shop, which has five deliberately planted violations. Tags were fetched once from a cache. Vendor endpoints recorded zero hits.

Sessions16

Two regions, four consent states, plus withdrawal and chaos runs

Tag fetches80

Real tag code, fetched once without cookies or referrer

Reached a vendor0

Every outbound request was caught and answered locally

Planted violations5/5

All five caught, including a skimmer hidden in a fourth-party dependency

The test persona

Meet Foolia. She doesn't exist.

Foolia is the visitor in every run. Her name, email, phone and card number are fabricated, and each value is a canary tied to that run. If any of it shows up in an outbound payload, Faraday finds it, whether it's sent raw, URL-encoded, base64, hex or hashed.

Foolia withdrew consent. AdNet recognized her anyway.Re-identified in a clean session and re-linked to her old profile.
Foolia said no. MetricsCo kept her ID._mx_id written to localStorage without analytics consent. The network tab looked clean.

Both are real findings from the demo shop run.

Synthetic visitorFD-132370
Name
Foolia
Email
cr-132370@canary.test
Phone
+1 555 0100
Card
4000 0068 3184 8808
Born
1970-01-01
Consent
Reject all · GPC on
Region
EU-DE, US-CA
canary · traceable

How a run works

Five steps. The first one is a lock.

Faraday won't start a run against any domain until written permission for that domain is on record.

  1. AuthorizeRecord written permission for the domain. Without it, the run doesn't start.
  2. Create FooliaFabricate a persona with canary values. Real personal data is rejected.
  3. Seal the browserDNS is disabled. Tags load for real, and every outbound request is caught at the wall.
  4. Run the matrixConsent choice × region × GPC × journey, recorded so any run can be replayed exactly.
  5. Report and gateAn HTML and JSON report with evidence. A new violation fails the build.

Consent as a test matrix

"Reject all" isn't a single test.

Findings per cell from the demo run. Saying no in Germany produced as many findings as saying yes, because the planted tags ignore the choice.

Consent choiceEU-DEUS-CA
No choice made22findings20findings
Accept all26findings22findings
Analytics only26findings22findings
Reject all26findings24findings

What the run caught

AdNet sends data before the visitor choosespre-consent egress
AdNet ignores Global Privacy Controlgpc-ignored
MetricsCo writes IDs to IndexedDB without consentstorage-without-consent
AdNet re-identifies Foolia after withdrawalreidentified-in-clean-session
Card number sent to an unknown host via a fourth-party scriptpayment-data-exfiltration

Datasheet

What it checks

Each row is labeled with its real status. Prototype and roadmap rows aren't for sale yet.

CapabilityWhat it showsStatus
Consent test matrixConsent choice × region × GPC × journey, each run compared against what that consent allowsShipping
Storage-layer auditIDs written to cookies, localStorage or IndexedDB, attributed to the script that wrote themShipping
Canary PII and skimmer detectionSynthetic email, phone and card values found in any payload: raw, URL-encoded, base64, hex, SHA-256, SHA-1, MD5Shipping
Payment-field watchThird-party scripts that read or listen to card fields, with the full load chainShipping
Withdrawal testingTraffic after consent is revoked, re-linking to old profiles, and re-identification compared against a control personaShipping
Consent chaos testsConsent manager down or slow, corrupted consent state, consent flipped mid-journey, vendor failureShipping
Dark-pattern scoreAccept vs. reject size, clicks needed and time cost of refusing, tied to enforcement precedentShipping
Tag tree and driftScript fingerprints and load chain, with an alert when they change without a deployShipping
Exfiltration channelsContent-Security and Permissions policies checked against observed traffic, plus DNS, WebSocket and WebRTC leak pathsShipping
Inference risk scoreWhat a vendor could work out about the visitor from the outbound dataPrototype
Server-side tagsThe server-side leg of tag and conversion pipelinesRoadmap
Cross-site viewWhether a partner's ad stack recognizes a persona that opted out somewhere elseRoadmap · legal review

Under the hood

A CLI that fails the build

It runs on your machine or in your CI pipeline. Reports stay with you.

faraday audit --all
$ faraday audit -c run.json --all --fail-on high
✓ authorization  shop.test (SOW §3, on record)
✓ persona        foolia · synthetic · canary cr-132370
✓ sandbox        DNS sealed · 80 tag fetches · egress 0
▸ matrix         16 sessions · replayable
✕ critical  64  card number → stats-cdn.test (base64)
✕ high      81  AdNet beacon before consent choice
! medium    43  hashed email → AdNet (with consent)
· low       17
→ out/demo/full-audit.html
exit 1 (--fail-on high)

Technical specs

Runtime
Node 20+, with a headless browser engine
Interface
audit, diff, drift, verify-replay
CI
Sample workflow included. The run exits non-zero on --fail-on
Outputs
JSON artifact and an HTML report with evidence for each finding
Replay
Seeded randomness and a frozen clock: record once, replay twice, diff
Data
Synthetic personas only. Real personal data is rejected at the gate
Tests
40 unit and 7 integration tests

How it stays safe

  • Runs only against domains with written authorization on record.
  • The browser can't open a connection on its own. Every byte goes through one boundary, and outbound requests to vendors are answered locally.
  • Personas are fabricated. Every canary value traces back to the run that created it.
  • The browser stays on the authorized property. Cross-site mode is deliberately not built.

What it isn't

A finding shows what one browser did under one consent choice at one moment. It's evidence for a review, not a legal opinion or a certificate of compliance. Region is emulated by timezone, locale and location, so sites that target by IP need a proxy. Every engagement starts with a check that the consent-banner clicks actually land, because a misconfigured run produces a clean report that means nothing.

Closed beta

One property. 30 days. A report you can act on.

Faraday is in closed beta with a small group of privacy, legal and marketing-tech teams. Send me a LinkedIn message with a line about the property you'd test. Pilots run on sites you own or are contracted to audit.

Faraday · closed beta · a working name · Back to hord.brayden · Pixel Lab · Partner brief · Brand · Privacy