Privacy Controls
The tracker stores nothing on the visitor’s device and holds no personal data on an anonymous session, so there is little for a visitor to object to. It still gives them a way to object, and honours the browser-level objection they may already be sending.
Opt-out
Section titled “Opt-out”signals.optOut(); // stop tracking this visitor, now and on future visitssignals.optIn(); // resumesignals.optedOut; // booleanoptOut() writes a single flag to localStorage (snipform_optout = 1). This flag is the only thing Signals ever writes to a device, and only at the visitor’s own request - storing the objection itself is the one storage use every cookie regime permits. While it is set:
- The tracker never initialises on page load.
- Timers stop and listeners are removed on the current page; no further request leaves it, including the exit ping.
signals(),signals.acquisition()andsignals.identify()resolve{ success: false, error: 'Visitor opted out' }.
optIn() clears the flag and boots the tracker immediately, without a reload. Both return a promise that resolves true.
If localStorage is unavailable (private mode with storage disabled, locked-down iframes) the flag cannot be written and the tracker keeps running. The methods never throw.
A toggle
Section titled “A toggle”<label> <input type="checkbox" id="snip-optout"> Do not track my visits on this site</label>
<script> const box = document.getElementById('snip-optout'); const sync = () => { box.checked = !!window.signals?.optedOut; }; sync(); window.addEventListener('signals:ready', sync); box.addEventListener('change', () => { box.checked ? window.signals.optOut() : window.signals.optIn(); });</script>Put it on your privacy page. The flag is per origin, so a visitor opts out of your site, not of every site using SnipForm.
Global Privacy Control
Section titled “Global Privacy Control”A browser or extension sending Sec-GPC: 1 is making a legal objection to the sale, sharing and profiling of personal information. Anonymous analytics are none of those things, so the session is still counted. The one operation GPC can govern is turning an anonymous session into an identified person, and that is what it blocks:
signals.identify()on a GPC browser returns{ success: true, contact_id: null, linked_to_session: false, gpc: true }. No contact is created or updated, nothing is linked.- Server-side identify through the API is your call to make, since the header belongs to the browser request, not to your server.
You do not have to do anything to get this behaviour; the check happens on the server for every identify request.
What is and is not collected
Section titled “What is and is not collected”| Never | Always discarded | Kept on the session |
|---|---|---|
| Cookies, localStorage (except the opt-out flag), sessionStorage | Raw IP address, raw user agent string, the inputs to the session hash | Page URLs and titles, referrer, viewport, browser and OS family, device class, country and city, time on site, scroll depth, your events |
Two consequences you should design around:
- Keep personal data out of URLs and event meta. Page URLs are stored as sent. A
?email=parameter or a name in a path becomes part of the session record. The same goes forsignals('...', { email }). - Identify is the line. A session with a contact linked is personal data and is treated as such: it is exportable and erasable per contact, and deleting the contact redacts it in place. See Identify and Contacts.