Legal
What Metricward collects on a customer's behalf, about that customer's own visitors, field by field, and what it deliberately does not collect.
This is the detailed version of /privacy, same subject, full detail. It does not cover the data Metricward holds about its own account holders, their name, email and billing details, which are governed by the same privacy page and by ordinary controller obligations, not by this document.
A visitor is not identified by name or email. Each project has a daily salt held only in Redis with a 24-hour lifetime, never written to disk, never included in a backup and never logged. The visitor identifier is an HMAC of that salt. When the salt expires, every hash computed with it becomes permanently unlinkable to anything, including the IP address that fed it, which is what makes the anonymisation retroactive rather than a promise about the future. Because the salt is scoped to one project, the same person on two different customers' sites produces two unrelated hashes, there is no shared key that could join them.
The IP address is available to the ingestion process as a connection property. It is used for two things, a country lookup against a local geo database and the daily salted hash, both in memory, and then it is discarded. No table in any store has a column that could hold a raw IP, so this is not a redaction step applied to something already collected, the value never exists anywhere a raw IP could be read back from.
Set per project, not per event.
| Mode | Visitor identifier lifetime | What it is for |
|---|---|---|
| cookieless | 24 hours | Aggregate traffic analytics with no durable identifier at all. |
| cookie | 12 months | Cross-session analytics for anonymous visitors, using a stored identifier. |
| identified | Same as the mode above, plus a permanent user id | Cross-device, cross-session truth once a customer calls identify(). |
Identified analytics adds a permanent, customer-controlled user_id on top of whichever mode is active, set only when the customer calls identify(). It is the one identifier Metricward treats as authoritative rather than a heuristic about a browser, and merge rules are deliberately conservative: two different people are never fused into one identity, even at the cost of occasionally under-merging the same person.
Not required.
Collection proceeds in cookieless mode without waiting for a signal. This is the customer's legal judgement, not ours, that their configuration does not require consent.
Required.
Events buffer in the browser until consent is granted. If consent is denied, the buffer is discarded and nothing is sent.
Required, strict.
Nothing is sent at all, not even a buffered count, until consent is granted. The largest measurement gap of the three, and the product says so rather than hiding it.
Global Privacy Control and Do Not Track are each honoured by default and independently toggleable per project. When either signal suppresses collection, only an aggregate daily counter increments, never a per-visitor record, because keeping a log of who specifically refused consent would be its own processing problem.
| Field | What is actually stored |
|---|---|
| event id, timestamp | A generated event id and the time the event occurred and was received. |
| path | The URL path, with identifier-shaped segments (ids, UUIDs, emails) masked to a pattern like /users/:id before storage. |
| hostname, title | The page's hostname and title as sent by the SDK. |
| referrer | Host and a masked path. Internal referrers, from the same site, are dropped entirely. |
| channel, utm_* | A classified acquisition channel plus the standard utm_* values. The click identifier itself (gclid, fbclid and similar) is never stored, only the fact that a paid click of that kind occurred. |
| country | A country code from a local geo database file. Region and city are stored only if a project explicitly raises its geo precision above the default. |
| device type, browser, os | Coarse categories: desktop, mobile, tablet. Browser is stored to its major version only, never a full version string. The raw user-agent string is discarded immediately after parsing. |
| screen size | Bucketed into a small set of ranges, never the exact resolution. |
| language | The browser's reported language. |
| duration, scroll depth, revenue | Engagement time and scroll depth for the page; revenue amount and currency only for events a customer explicitly sends as a purchase or conversion. |
| properties | Whatever a customer's own tracking code attaches to an event. See the note below the table. |
| is_bot, consent, source | Whether the event was flagged as a bot and why, the consent state it was sent under, and whether it came from a browser, a server, an import or a proxy. |
Custom properties are the exception to all of the above: whatever a customer's own tracking code sends in an event's properties is stored as sent, because a property is the customer's own data model and silently rewriting it would corrupt it. Putting an email address or a token in a property is a risk the customer creates for themselves, and the acceptable-use section of our terms asks customers not to put special-category data there.
Off by default, project by project. When it is on, masking happens in the browser before anything is sent, so the server never receives the real text and cannot leak what it never had. Input, textarea and select values are never captured, in any configuration. Password, email, phone and payment-shaped fields are not serialised at all, and a structure-only mode is available that captures layout and interaction with no text at all, not even masked placeholders.
A server-side check runs on the masked stream as a backstop: a chunk that still looks like it contains an email address, an IBAN, a card number or a Nordic identity number is refused and never stored, for the case where a customer's own custom component renders sensitive text outside a normal input. Default retention is 30 days, 90 days maximum, enforced by an object-storage lifecycle rule. A kill switch disables capture for a project immediately, reaching an already-open browser tab within roughly 90 seconds in the worst case, and the server-side refusal above is the real backstop for that window rather than relying on the switch alone.
Retention is a per-project setting, plan-capped, enforced by a nightly job rather than a policy nobody runs: whole expired months are dropped outright, the remainder is deleted individually, and the job verifies its own result with a follow-up count before it reports success. Every deletion, whether it is routine retention, a subject access request, or a project or account closure, writes a deletion_receipts row with per-store row counts before and after. A customer asking us to prove a deletion happened gets a receipt with a job id, not a reassurance. Deleted data leaves backups as the rolling backup window ages out rather than instantly, and that is stated here rather than claimed away.
Related: privacy, processor terms, compliance, security.
Nothing on this page is legal advice. If it matters to your organisation, have it checked by someone whose job that is.