Consent
Choose between consentless and full mode, pass consent answers from your banner, and honour Do Not Track, GPC and your own visits.
MIRA FIVE collects in one of two modes. Consentless mode, the default in the browser, sends no identifiers, stores nothing on the device and needs no consent banner. Full mode adds ids and device details, and waits for the visitor's consent. Pick the mode per page with the SDK, and wire your consent manager only if you use full mode.
Consentless mode
The script tag and the browser SDKs start in consentless mode. Each batch carries:
- the batch id, the send time and the SDK name and version (
context.sdk); - per event: the name, the time, the page (the cleaned URL, title and referrer) and your properties.
It never carries an anonymous id, a session id, a user id, the browser's language, time zone or screen size. The SDK does not read those values at all, sets no cookies and writes nothing to localStorage or any other storage. The server refuses a consentless batch that carries ids or device details (400 validation_failed), so a misconfigured client shows up at once.
What you give up:
identify(), site search and experiment exposures:$identify,$searchand$exposureare dropped from consentless batches.- Per-visitor flags. A consentless page receives only the answer each flag gives everyone, so percentage rollouts, targeting rules and experiments do not run. See Feature flags.
Nothing to set up: this is the default. On the script tag, consent, identify and reset do nothing in this mode, silently, and anonymousId answers undefined, so consent wiring can stay in place when you switch modes.
Full mode
Full mode is for visitors who consented. Turn it on with data-mode="full" on the script tag, or mode: 'full' and the identity() plugin in the browser SDK:
import { createMira } from '@mirafive/sdk-browser'
import { identity } from '@mirafive/sdk-browser/identity'
import { pageviews } from '@mirafive/sdk-browser/pageviews'
export const mira = createMira({
key: import.meta.env.VITE_MIRAFIVE_KEY,
mode: 'full',
plugins: [pageviews(), identity()],
})Until the visitor answers, full mode sends nothing and stores nothing. It remembers the landing pageview and sends it when statistics consent is first granted, so a visitor who accepts on the first page still counts that page. A visitor who declines, or never answers, is not counted.
With statistics consent, each batch carries everything consentless mode sends, plus:
| Field | Value |
|---|---|
anonymousId | A UUID for the browser, stored for 365 days since last seen |
sessionId | A UUID for the visit, stored until 30 minutes without an event |
userId | Your id, after identify() |
context.locale | The browser language, for example de-DE |
context.timezone | The IANA time zone, for example Europe/Berlin |
context.screen | The screen width and height |
$boot: 1 on $pageview | The consent answer was known when the page first drew |
Ids are stored in localStorage only, never in cookies. Identify users lists the entries. Full mode also allows site search, experiments and segment targeting.
Source mode
Each website source in MIRA FIVE also has a mode, and it is a ceiling:
| Source mode | Consentless batches | Full batches | Flags served |
|---|---|---|---|
| Full | Accepted | Accepted | Per-visitor rules; segment lookups with targeting consent |
| Consentless | Accepted | Refused, 400 collection_mode_not_allowed | The answer for everyone only; a segment lookup is refused with 403 lookup_not_allowed |
A full source is the flexible choice: the page decides per visitor. Set the page to full mode only when the source is full too.
Consent answers
In full mode, pass your consent manager's answer to consent(). There are three scopes:
| Scope | Allows |
|---|---|
statistics | Sending events with ids and device details, and storing the ids |
experiments | Using the anonymous id for flag rollouts and experiments, and sending $exposure events |
targeting | Looking up which of your segments the visitor is in, to target flags |
The answer is one of:
| Answer | Meaning |
|---|---|
true | Statistics only |
{ statistics, experiments, targeting } | By scope. A scope you leave out keeps its last answer |
false | Forget the ids and the user, remove the stored entries and clear the queue |
Events need statistics consent: without it, full mode sends nothing, whatever the other scopes say. Exposures need statistics and experiments. Call consent() again whenever the visitor changes their choice.
Wire a consent manager
Map your consent manager's categories to the three scopes. Statistics is usually the "analytics" or "statistics" category, targeting the "marketing" one.
<script>window.mirafive=window.mirafive||function(){(mirafive.q=mirafive.q||[]).push(arguments)}</script>
<script defer src="https://cdn.mirafive.io/mira.js" data-key="mf_…" data-mode="full"></script>
<script>
window.addEventListener('CookiebotOnConsentReady', () => {
const { statistics, preferences, marketing } = Cookiebot.consent
mirafive('consent', { statistics, experiments: preferences, targeting: marketing })
})
</script>The identity code downloads on the first grant. A decline downloads it only when the browser still holds ids from an earlier visit, to remove them.
Answer before the SDK loads
A consent manager that already knows the stored answer can set it before the SDK starts:
<script>
window.__mirafive_consent = { statistics: true, experiments: true, targeting: false }
</script>
<script defer src="https://cdn.mirafive.io/mira.js" data-key="mf_…" data-mode="full"></script>window.__mirafive_consent is false or an object of the three booleans. The SDK applies it at start, so the landing pageview is sent with the answer and marked $boot: 1, and the script tag loads its identity code at once. The page-experiment snippet reads it too. On the script tag, a mirafive('consent', …) call queued before mira.js has run counts the same way.
Do Not Track and Global Privacy Control
When navigator.doNotTrack is "1" or navigator.globalPrivacyControl is true, the browser SDKs send nothing, in both modes. Flags still answer, but without the anonymous id, without a segment lookup and without exposures, so the visitor sees what someone without an id sees.
On the server side:
- A browser request with
Sec-GPC: 1orDNT: 1turns a full batch into a consentless one: the server keeps the events without their ids and drops$identify,$searchand$exposure. - Server flag reads take the visitor's opt-out as
optedOut: true.flagsFor()from@mirafive/sdk-next/serverand the Laravel package read both headers for you. See Feature flags. - For server events about an opted-out visitor, leave the ids out, or send them with a consentless client.
Ignore your own visits
Set window.__mirafive_ignore = true and the page sends nothing from this browser: no events, no flag ids, no exposures, and page experiments show the original. Render it only for your own team, for example when an admin is signed in:
<script>
window.__mirafive_ignore = true
</script>The SDK checks it on every event, so it also works when set after the SDK has loaded.
Server events and mode
Server SDKs default to full mode: userId, anonymousId and sessionId are allowed, and you hold the consent or other lawful basis for them. Switch a server client to consentless mode to count without ids, for example invoices or anonymous totals:
import { Mira } from '@mirafive/sdk-server'
const mira = new Mira({ key: process.env.MIRAFIVE_SECRET_KEY, mode: 'consentless' })
mira.track('invoice paid', { properties: { revenue: 99, currency: 'EUR' } })Passing an id then throws a TypeError.
The source's mode is a ceiling here too: a consentless server source refuses full batches. More in Server-side events.