Experiments
Run A/B tests with flags or page snippets, and know exactly when a visitor is counted in an experiment.
An experiment splits visitors between variants and compares what they do next. MIRA FIVE runs two kinds: flag experiments, where your code reads a feature flag and shows the variant, and page experiments, where a snippet in the page head swaps marked elements without code. Both count a visitor with an $exposure event, which needs full mode and consent.
Flag experiments
A flag experiment is a flag that MIRA FIVE counts. You read it like any other flag, where you show the variant:
<script>
mirafive('flags', () => {
const variant = mirafive('flag', 'pricing-test', 'a')
document.querySelector('#price').textContent = variant === 'b' ? '€19 / month' : '€190 / year'
})
</script>The page needs full mode with the identity() and flags() plugins (data-mode="full" on the script tag), and the visitor's experiments consent to be counted. Without it, the visitor sees a variant but is not counted.
Exposures
An exposure is the $exposure event that says "this unit saw this variant". MIRA FIVE compares variants only among exposed units. It carries:
| Property | Value |
|---|---|
$experiment | The flag key |
$variant | The variant shown |
$boot | Browser only: 1 when the consent answer was known when the page first drew, else 0 |
$snippet | Page experiments only: the hash of the snippet copy that drew the variant |
An exposure is sent only when all of these hold:
- The unit was drawn into the variant by the experiment's split. A visitor who gets a fixed variant from a rule, or falls outside the experiment's share, is not counted.
- The flag is read where the experiment is counted: in the browser or on the server (see Where it is counted).
- The read uses the value:
flag(),config(),useFlag(),useFlagConfig(), orenabled(),variant()andconfig()on a server.evaluate(),onFlagslisteners themselves, overrides and previews never count. - In the browser: statistics and
experimentsconsent are granted, and the id the unit is counted under still gives the same variant. Exposures read before the grant wait for it and are dropped on a decline. - Nobody opted out: no Do Not Track, Global Privacy Control or
__mirafive_ignore.
So read an experiment's flag only where you show its variant: a read in code that decides nothing still counts the visitor.
Deduplication: a browser sends at most one exposure per flag per page load. A server sends at most one per flag, variant and unit per hour; PHP shares that mark between processes through the cache you pass.
Exposures are needed for results but are not counted against your event allowance.
Where it is counted
Each experiment is counted either in the browser or on the server; you choose when you create it in MIRA FIVE.
| Counted in | Read it with | Server reads |
|---|---|---|
| The browser | A browser SDK | Answer the default variant with the error code NOT_ALLOWED, and count nothing |
| The server | A server SDK with a full-mode client | Count the exposure |
A server-rendered page can still show a browser-counted experiment without flicker: the bootstrap block carries the server's decision to the page, and the browser counts it when the page reads the flag. For an experiment assigned by person, the browser counts it only when the page has called identify() with the same user id the server used.
Before consent
An experiment can run before the visitor answers the consent banner, in one of two ways, set per experiment in MIRA FIVE:
| Before consent | The visitor sees |
|---|---|
| Random | A random variant, drawn with a pending id kept in page memory (window.__mirafive_aid_next). On consent it becomes the anonymous id, so the visitor keeps the variant |
| Original | The default variant, until experiments consent is granted |
Either way, nothing is stored and no exposure is sent before consent. A page keeps the variant it first showed for the whole page load.
Page experiments
A page experiment swaps parts of a page without code. It needs a full website source and a page in full mode.
- In MIRA FIVE, create the page experiment and copy its head snippet: a
<style>and a<script>. - Paste the snippet into
<head>, above the MIRA FIVE script. - Mark the original and the new version of each element with the experiment key and the variant,
afor the original andbfor the new one.
<head>
<!-- The page-experiment snippet from MIRA FIVE goes here, above the script tag -->
<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>
</head>
<body>
<h1 data-mirafive-experiment="hero-copy" data-mirafive-variant="a">Analytics without cookies</h1>
<h1 data-mirafive-experiment="hero-copy" data-mirafive-variant="b">Know what works on your site</h1>
</body>The snippet runs before the page draws. It picks a variant, sets data-mirafive-hero-copy="b" on <html>, and its style hides every marked element of the other variant. It stores nothing and sends nothing. When it drew with an id, it pushes its decision onto window.__mirafive_experiments, and the browser SDK sends the exposure once experiments consent is granted and the anonymous id gives the same variant.
The script tag loads its experiments code by itself when a snippet has decided something. With the npm package, add the experiments() plugin next to identity() and flags():
import { createMira } from '@mirafive/sdk-browser'
import { experiments } from '@mirafive/sdk-browser/experiments'
import { flags } from '@mirafive/sdk-browser/flags'
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(), flags(), experiments()],
})Details:
- The snippet shows the original, and counts nothing, on hosts that are not the source's allowed origins (or their
www.twins), after the expiry date built into the snippet (at least 180 days after it was generated), under Do Not Track, Global Privacy Control or__mirafive_ignore, and while the page is prerendering. - It reads
window.__mirafive_consent, so set that before it runs when your consent manager knows the answer. mira.flag('hero-copy', 'a')returns the variant the snippet chose.- Preview a variant on any host with
?mirafive-preview=hero-copy:b. - When MIRA FIVE switches an experiment to show everyone the original (it was decided for the original, or ended early), the SDK answers
a, setsdata-mirafive-hero-copy="a"and sends no exposure, even while the snippet is still in the page. Remove the snippet and the markup of the variant you drop when you are done.
Server-side experiments
An experiment counted on the server is read with a server SDK whose flag client can send events. Pass the visitor's experiments consent; without it the anonymous id is not used and nobody is counted:
import { Mira } from '@mirafive/sdk-server'
import { MiraFlags } from '@mirafive/sdk-server/flags'
const mira = new Mira({ key: process.env.MIRAFIVE_SECRET_KEY })
const flags = new MiraFlags({ key: process.env.MIRAFIVE_SECRET_KEY, mira })
const user = await flags.for({ userId: session.userId, consent: { experiments: true } })
const variant = user.variant('onboarding-emails', 'a')mira must be in full mode: a consentless client counts no exposures and reports collection_mode_not_allowed to onError. With a waitUntil, the exposure is flushed with the request.
Rendering a bootstrap block for a unit counts every server-counted experiment it decided for that unit, since the page is handed the value.