Privacy & Opt-Out
Pomelo Analytics is built around a privacy-first, cookieless-by-default approach. This page documents Pomelo’s current collection boundaries and how to give your visitors control.
Doctrine note: Pomelo is moving toward a Strict by default / Extended by configuration model. This page documents the privacy baseline and opt-out controls. It documents boundaries rather than making a legal-status promise for every Pomelo surface.
What Pomelo does NOT do
Section titled “What Pomelo does NOT do”- No measurement cookies — Pomelo does not set, read, or require cookies for analytics measurement. The only cookie used is the first-party opt-out cookie when a visitor explicitly objects.
- No localStorage / sessionStorage — No data is stored on the visitor’s device (except the opt-out objection cookie, see below).
- No fingerprinting — No canvas, WebGL, font enumeration, or other browser fingerprinting techniques.
- No cross-site tracking — The daily visitor key is scoped per site and cannot link visitors across different domains.
- No IP storage — IP addresses are used only transiently for pseudonymization (HMAC) and geolocation, then discarded.
- No user profiles — Pomelo does not build behavioral profiles or advertising segments.
DNT & GPC enforcement
Section titled “DNT & GPC enforcement”Pomelo always respects Do Not Track (DNT) and Global Privacy Control (GPC) signals. This is not opt-in — it is enforced unconditionally:
- Client-side: The tracking script checks
navigator.doNotTrackandnavigator.globalPrivacyControl. If either is enabled, no events are sent. - Server-side: The ingest API checks
DNT: 1andSec-GPC: 1headers. Events with these headers are silently dropped as defense-in-depth.
Opt-out API
Section titled “Opt-out API”Pomelo provides a JavaScript API for visitors to opt out of measurement:
pomelo.optout(true)
Section titled “pomelo.optout(true)”Stops all tracking immediately:
- Sets a first-party cookie
pomelo_optout=1(valid 1 year,SameSite=Lax) - Sets
window.__POMELO_OPTOUT__ = true - Clears any pending event queue
pomelo.optout(false)
Section titled “pomelo.optout(false)”Re-enables tracking:
- Removes the
pomelo_optoutcookie - Deletes the
window.__POMELO_OPTOUT__flag
Example: Opt-out button
Section titled “Example: Opt-out button”<!-- Add to your privacy page or footer --><button id="pomelo-optout">Opt out of analytics</button><button id="pomelo-optin" style="display:none">Re-enable analytics</button>
<script> document.getElementById('pomelo-optout').addEventListener('click', () => { window.pomelo.optout(true); alert('You have opted out of analytics measurement.'); document.getElementById('pomelo-optout').style.display = 'none'; document.getElementById('pomelo-optin').style.display = ''; });
document.getElementById('pomelo-optin').addEventListener('click', () => { window.pomelo.optout(false); alert('Analytics measurement has been re-enabled.'); document.getElementById('pomelo-optin').style.display = 'none'; document.getElementById('pomelo-optout').style.display = ''; });</script>Alternative: Window flag
Section titled “Alternative: Window flag”You can also block tracking before the script loads by setting the global flag:
<script> window.__POMELO_OPTOUT__ = true;</script>The opt-out cookie
Section titled “The opt-out cookie”The pomelo_optout=1 cookie is a first-party cookie that stores only the
visitor’s objection. It is:
- Not a tracking identifier — it contains no unique value.
- First-party only — set on your domain, not a third-party domain.
- SameSite=Lax — not sent in cross-site requests.
- Valid for 1 year — so the visitor does not need to opt out on every visit.
This cookie is only set when the visitor explicitly opts out. Pomelo does not set any cookies during normal measurement.
Consent and banner reading
Section titled “Consent and banner reading”Pomelo alone is designed to support a minimized audience-measurement setup only when you stay inside the documented strict envelope.
This does not mean:
- every Pomelo surface has the same legal reading
Extendedcan be treated as a consent-light default- your whole site can remove its banner without reviewing the rest of its trackers
If the page also loads ad tech, personalization tags, session replay, or any other consent-requiring tracker, the site can still require consent UI independently of Pomelo.
Data minimization summary
Section titled “Data minimization summary”| Data point | Stored? | Details |
|---|---|---|
| IP address | No | Used transiently for HMAC + geolocation, then discarded |
| Cookies | No | Only pomelo_optout if the visitor explicitly opts out |
| User agent | Server-side only | Parsed from the HTTP header for device/browser/OS classification; never sent from the browser |
| Page URL | Yes | Canonicalized URL with hash removed; Strict drops query params, Extended can keep an allowlisted acquisition subset |
| Referrer | Yes | Strict keeps host-based referrer reads; full referrer values stay outside the default strict envelope |
| Geolocation | Yes | Country can stay in the strict baseline; region/city remain enriched slices |
| Daily visitor key | Yes | HMAC, resets at UTC midnight, scoped per site |
| Session ID | Pseudonymized daily key | HMAC of domain + day + IP + browser family; no raw UA used |
Automatic data sanitization
Section titled “Automatic data sanitization”The tracking script applies automatic sanitization to captured text as a defense-in-depth measure against accidental PII leakage.
- Identifiers (
data-analytics-id,data-analytics-scope, form IDs): safe charset only (a-z,0-9,_,-,.,:,/, space), max 100 characters. Dropped entirely if PII is detected. - Labels (
data-analytics-label, auto-detected labels): max 80 characters. Dropped entirely if PII is detected. - Page titles: max 200 characters. Dropped entirely if PII is detected.
- Error messages: query strings stripped, PII patterns replaced
with
[redacted], max 200 characters, and only when enriched error capture is enabled.
PII patterns detected include:
- Email addresses
- Phone numbers
- UUIDs
- Long numeric sequences (10+ consecutive digits)
- Token-like strings (20+ alphanumeric characters)
If in doubt, the SDK drops the field instead of sending it.
What the SDK will ignore
Section titled “What the SDK will ignore”The SDK silently drops values that look unsafe or overly sensitive, including:
- Email addresses
- Phone numbers
- UUIDs
- Long numeric sequences
- Token-like strings
- Free-form text from form fields
- Text from
contentEditableregions
This is intentional: Pomelo prefers losing a data point over transmitting sensitive data.
See also: SDK Integration for the full attribute reference and sanitization rules.