Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 1.0.1 (2026-03-04)

### Documentation

- **Privacy documentation** — Added `PRIVACY.md` and dedicated privacy guide (`docs/privacy.md`) with signal inventory, cookie details, fingerprinting risk assessment, consent integration examples, data subject rights, and regulatory guidance (GDPR, ePrivacy, CCPA, LGPD)

## 1.0.0 (2026-03-04)

### Breaking Changes
Expand Down
62 changes: 62 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Privacy

DeviceRouter collects device capability signals to classify devices and derive rendering hints.
This document summarizes what is collected, what is not, and where to find detailed guidance.

## What is collected

The client probe reads the following signals via browser APIs:

- CPU core count (`hardwareConcurrency`)
- Device memory (`deviceMemory`)
- Connection type, downlink speed, RTT, data saver mode (`navigator.connection`)
- Pixel ratio (`devicePixelRatio`)
- Prefers reduced motion / color scheme (`matchMedia`)
- GPU renderer (WebGL debug info)
- Battery level and charging status (`navigator.getBattery()`)

All signals are optional — the probe gracefully degrades based on what the browser supports.

## What is NOT stored

- **User agent** — collected for bot/crawler filtering, then stripped before storage
- **Viewport dimensions** — collected for bot/crawler filtering, then stripped before storage

These two fields never reach the storage layer.

## Cookie

DeviceRouter sets a single session cookie:

| Attribute | Value |
| ---------- | ----------------------- |
| Name | `device-router-session` |
| `httpOnly` | `true` |
| `sameSite` | `lax` |
| `secure` | `false` (configurable) |
| `path` | `/` (configurable) |
| Max age | 24 hours (configurable) |

The cookie value is a random UUID v4 (`crypto.randomUUID()`). It contains no user data — it is
solely a key to look up the stored device profile.

## No tracking, no profiling

- Profiles are tied to random session tokens, not to users or accounts
- No data is shared with third parties
- No cross-session or cross-site tracking
- No personally identifiable information (PII) is collected or stored

## Regulatory implications

Depending on your jurisdiction, collecting device signals and setting a cookie may require user
consent. DeviceRouter provides the technical building blocks but does **not** include a consent
mechanism — that is your responsibility.

For detailed regulatory guidance (GDPR, ePrivacy, CCPA, LGPD) and consent integration examples,
see the [Privacy Guide](docs/privacy.md).

---

> **Disclaimer:** This document is informational guidance, not legal advice. Consult a qualified
> privacy professional for your specific deployment.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ Open http://localhost:3000 — the probe runs on first load, refresh to see your
## Documentation

- [Getting Started](docs/getting-started.md)
- [Privacy Guide](docs/privacy.md) — Signal inventory, cookie details, consent integration, GDPR/CCPA/LGPD guidance
- [Observability](docs/observability.md) — Logging, metrics, and monitoring hooks
- [Deployment Guide](docs/deployment.md) — Docker, Cloudflare Workers, serverless
- [Meta-Framework Integration](docs/meta-frameworks.md) — Next.js, Remix, SvelteKit
Expand Down
40 changes: 2 additions & 38 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,45 +306,9 @@ const storage = new RedisStorageAdapter({

## Privacy and Cookie Consent

DeviceRouter collects device capability signals (CPU cores, memory, GPU renderer, viewport, connection type, battery status, user agent) and links them to a session cookie. Depending on your jurisdiction, this has regulatory implications.
DeviceRouter collects device capability signals and links them to a session cookie. Depending on your jurisdiction (EU, UK, California, Brazil, and others), this has regulatory implications — you may need to obtain user consent before loading the probe script.

### Collected signals and fingerprinting

The signals DeviceRouter collects overlap with known browser fingerprinting vectors. Regulators evaluate the _capability_ of the data to identify users, not just the stated intent. Even though DeviceRouter uses these signals solely for adaptive rendering, the combination of GPU renderer, hardware concurrency, device memory, viewport, and user agent can narrow down device identity — and regulators treat that as personal data.

### EU: GDPR and ePrivacy Directive

Two regulations apply independently:

- **ePrivacy Directive (Article 5(3))** covers both setting the `device-router-session` cookie _and_ reading device signals from browser APIs. Both count as accessing information stored on terminal equipment. The "strictly necessary" exemption is interpreted narrowly by the EDPB, CNIL, and ICO — it requires that the service _cannot function_ without the data, not that it functions _better_ with it. Adaptive rendering has not been recognized as strictly necessary by any regulator.

- **GDPR** applies because the collected signals in aggregate constitute personal data (Recital 30 explicitly references device identifiers and the profiles they can create). You need a lawful basis under Article 6 — consent (Article 6(1)(a)) is the most defensible option.

**In practice:** implement a cookie consent mechanism before deploying DeviceRouter in the EU.

### UK

The UK GDPR and PECR follow the same framework as the EU. The ICO has been particularly vocal about fingerprinting-like techniques — treat the requirements as equivalent.

### California (CCPA/CPRA)

The collected signals qualify as personal information under CCPA. You must:

- Disclose the collection in your privacy notice (notice at collection)
- Honor access and deletion requests for stored profiles
- If you never sell or share the data with third parties, the "Do Not Sell" opt-out does not apply, but the data is still subject to consumer rights

### Brazil (LGPD)

The ANPD treats cookie and fingerprinting data as personal data. Consent must be "free, informed and unequivocal." There is no "strictly necessary" carve-out equivalent to the ePrivacy Directive.

### Recommendations

- Obtain consent before loading the probe script in jurisdictions that require it
- Include DeviceRouter's signal collection in your privacy policy
- Set a reasonable TTL — shorter sessions reduce the regulatory surface
- Use `MemoryStorageAdapter` or configure Redis key expiration so profiles are not retained beyond their useful life
- Consider omitting high-entropy signals you do not need (e.g., if you only need CPU/memory tiers, you may not need `gpuRenderer` or `battery`)
For a full signal inventory, fingerprinting risk assessment, cookie details, consent integration examples, and jurisdiction-specific guidance, see the [Privacy Guide](privacy.md).

> **Note:** This section is informational guidance, not legal advice. Consult a qualified privacy professional for your specific deployment.

Expand Down
Loading