Exactly what the SDK collects
Field-level transparency, per privacy mode — and the hard list of what is never read or transmitted.
Enforced on the server too
This page describes SDK 1.13.0. Where a field arrived later than 1.0, the version is given.
The limits on this page are enforced server-side as well as in the SDK: the ingest API rebuilds every payload from a strict allowlist and rejects sensitive-looking values (raw emails, phone numbers, card patterns, password-like fields), so bypassing the SDK cannot store undocumented data. Raw request payloads are never persisted.
Free Preview sites also contribute pseudonymized, infrastructure-level sightings to the FindIP Threat Network: network-level data only, identical in every privacy mode, never including anything from the sections below.
Collected
By privacy mode
In every privacy mode
- Event name, timestamp and source (sent by your code, or detected by the SDK; a detected event also carries a confidence value and how it was detected)
- Page URL, path, title and referrer
- UTM parameters, and whether the URL carried a
gclidorfbclid(yes or no, never the value) - Session ID, and where the browser keeps it (1.11.0)
- SDK name, version and integration; in a mobile app's WebView, the app id you configure (1.13.0, see Mobile apps)
- Browser user agent, language and time zone
- The privacy mode in force and the consent state
- On form events: form metadata and the form outline (1.8.0): field types, the labels printed on the page and the button text
- Customer context and identity, only if your code provides them (see Customer context)
- When a form has a response configured: which response ran and how it ended
balanced and advanced: everything above, plus
- Visitor ID, and where the browser keeps it (1.11.0)
- The browser's language list, platform, and whether cookies are enabled
- Screen width, height and colour depth; viewport width and height
- Whether the device supports touch
- A form snapshot (1.9.0): a picture of a form with every value blanked, taken by one visitor's browser per form version, only when Shield asks for it
In SDK 1.12.0, advanced sends the same fields as balanced. The only difference in the payload is the retention hint (extended instead of standard).
strict: only the first list. No visitor ID, no localStorage, no screen or device details, and no form snapshot when strict is the mode you configured (see the consent case under Form snapshot).
The FindIP backend adds enrichment the SDK does not collect: visitor IP, ASN, geolocation, VPN/proxy/Tor/hosting/malicious flags, risk score and recommendation.
Never collected
In any mode, under any configuration
Form metadata
Sent with form events: a form coming into view, a form being submitted
{
"field_count": 2,
"has_email_field": true,
"has_password_field": true,
"has_phone_field": false,
"has_payment_field": false,
"has_message_field": false,
"submit_text_type": "signup",
"form_id": "signup-form",
"form_name": "signup",
"form_action": "/signup",
"outline": {
"fields": [
{ "type": "email", "label": "Work email" },
{ "type": "password", "label": "Password" }
],
"button": "Create account"
},
"outline_hash": "3fa9c1d2"
}field_countand thehas_*flags count the form's fields and say which kinds are present. They are worked out from each field'stype,name,id,autocomplete,placeholderandaria-labelattributes.submit_text_typeis a category for the submit button's text:signup,login,lead,checkout,payment,resetorgeneric.form_id,form_nameandform_action(SDK 1.3.0) are the form'sidandnameattributes and the path of itsaction(no host, no query string), each cut to 200 characters. They let the dashboard tell your forms apart.
Input values are never read or transmitted.
Form outline
Field types, labels and button text. SDK 1.8.0 and later, sent in every privacy mode
Form events also carry outline, so the dashboard can draw a recognisable mock of each form.
fields: up to 12 of the form's fields, in page order. Hidden inputs and buttons are skipped. For each field: itstype(the input type, orselectortextarea) and itslabel.labelis text from your page's markup, the first of these that exists: the field's<label>, itsaria-label, itsplaceholder, itsname.buttonis the text of the submit button.- Every label and the button text is cut to 40 characters. Text that looks like an email address, a phone number or a card number is dropped, in the SDK and again on the server.
outline_hash(SDK 1.9.0) is an 8-character hash of the outline, the form's CSS class names and its approximate width. Shield uses it to notice that a form has changed.
The outline is what your page prints around the fields. It never contains what a visitor typed. If your page writes personal data into a label or a placeholder (for example a placeholder showing the signed-in user's name), that text is part of the outline unless the filter above drops it.
Form snapshot: a picture of the empty form
SDK 1.9.0 and later. Not taken when strict is the mode you configured; turn it off with captureFormSnapshots: false
Shield can show a real picture of each form in the dashboard, next to its events. The picture is taken in a visitor's browser. This section says exactly what is in it.
When a picture is taken. When a form comes into view, the SDK reports it. If Shield has no picture of that form, the form has changed since the last one, or the picture is more than 30 days old, the response asks that browser for one. Shield asks one browser at a time, so one visitor per form version takes the picture and everyone else does nothing. A browser tries once per form version per browser session (it remembers the attempt in sessionStorage).
When no picture is taken.
- When the site's configured
privacyModeisstrict - When you set
captureFormSnapshots: false(see the SDK reference) - When the browser asks for reduced data use (data saver)
- While the tab is hidden; a tab that is never shown takes none
One case needs care. In SDK 1.12.0 the snapshot check reads the mode you configured, not the mode in force for the visitor. On a site configured as balanced or advanced with consentRequired: true and noConsentMode: 'strict', a visitor who declines consent is handled in strict mode for everything else on this page, but their browser can still be the one asked for a form picture. If that matters for your site, set captureFormSnapshots: false, or use noConsentMode: 'disabled' so that nothing at all is sent without consent.
What is drawn. Never the live form. The SDK copies the <form> element and, in the copy:
- empties every text, email, password, number, date and other input, and every
<textarea>and editable region - unticks every checkbox and radio button
- resets every
<select>to its first option - replaces every image with a blank pixel and removes its alt text
- replaces every embedded frame, video, audio, canvas or object (a captcha widget, a payment frame) with a blank box of the same size
- removes scripts
The copy is drawn off-screen with the page's own styles and encoded as a WebP or JPEG of at most 200 KB, covering at most 900 by 1200 CSS pixels of the form. The drawing library (html-to-image) is loaded from cdn.findip.net only at that moment.
What is uploaded. One request to /v1/shield/snapshot with the image, its width and height, your site key, the session ID, the page path, the form's form_id, form_name and form_action, and its outline_hash.
What is stored. The image, its size, the page path and the form's identifiers, one picture per form: a new picture replaces the old one. The session ID in the upload is not stored with the picture, so a picture is not linked to the visitor whose browser drew it. A form that has not been seen for 90 days loses its picture, and "Retake" in the dashboard deletes it at once.
What the picture can still show. Everything your page prints inside the <form> element as ordinary text: labels, placeholders, headings, help text, button text, the first option of each drop-down, and any error message visible at that moment. If your server prints personal data there as text rather than as a field value (for example "Signed in as [email protected]", a delivery address or an order summary inside the form), that text is in the picture, for the one visitor whose browser took it. If any of your forms does this, set captureFormSnapshots: false or use strict mode on those pages.
Browser storage
Two random IDs, and nothing else about the visitor
Cookies has the full list; in short:
- Session ID: the
_fip_sidcookie, copied tosessionStorage. A second cookie,_fip_ss, holds the same ID to mark that the session has started. - Visitor ID (not in
strictmode): the_fip_vidcookie and, since SDK 1.11.0, alocalStorageentry of the same name with the same lifetime. - When the browser refuses the session cookie (SDK 1.11.0):
sessionStorage, then the tab'swindow.name, then, only if you switch onlinkSession, a short-lived_fipparameter added to same-origin links at the moment they are clicked. - A
sessionStorageentry named_fip_snap:<outline hash>records that this browser already tried a form snapshot, so it does not try again.
When the browser stores nothing. Some browsers refuse all of the above. So that the pages of one visit still count as one session, Shield then derives a session ID on the server from data the request already carries: your site, the UTC date, the visitor's IP address, and the browser's User-Agent and Accept-Language headers, passed through a keyed hash (HMAC). Nothing is stored in the browser for this. The ID changes every UTC day and is different on every site. A visitor ID is derived the same way, except in strict mode. Derived IDs start with sess_cl_ and vis_cl_.
Two people on the same network with the same browser version and language get the same derived ID.
Customer context
Sent only if your own code provides it, in every privacy mode. The only fields FindIP.track() accepts:
user_id_hash, email_hash | Hashed identifiers |
email_domain | Domain only (e.g. gmail.com) |
account_age_days | Age of the account, in days |
plan, currency, transaction_amount | Business context |
form_name, lead_source | Attribution |
custom | Object with safe string/number/boolean values |
FindIP.identify() takes a plain user ID and email from your page and sends neither as given. It sends their SHA-256 hashes, the email's domain and, since SDK 1.1.0, a copy of each encrypted in the browser with your site's identity key (user_id_enc, email_enc). Only your Shield dashboard holds the key that opens them. See Identify users and add context.