Experiment Assignment & IDs

How Coframe assigns visitors to experiments and variants, and what the treatmentsDataV2 callback returns

Concept~7 min read

Copy this guide and your current settings as a prompt for your AI agent.

Preview agent promptSee the guide, code and settings included when you copy.

This page explains how Coframe assigns each visitor to an experiment and variant, what determines whether they see the original page or a treatment, and what the identifiers in the treatmentsDataV2 callback mean and how they relate to one another.

Watch: 70s — the eight callback fields, three example visitor payloads, and which IDs to use in analytics
On this page
  1. 01The treatmentsDataV2 Callback
  2. 02How a Visitor Gets Assigned
  3. 03Experiment Entity Hierarchy
  4. 04Frames with Multiple Experiments
  5. 05How Baseline and Treatment Visitors Are Grouped
  6. 06Callback Examples
  7. 07Dashboard vs. Callback IDs
  8. 08Using Callback Data in Analytics
  9. 09Summary

01The treatmentsDataV2 Callback

When a visitor is assigned to an experiment, Coframe calls the treatmentsDataV2 callback with a payload containing eight fields. Understanding these fields is the foundation for using Coframe data in your own analytics and attribution pipelines.

Field Type Description
coframe_experiment_id string Experiment ID shared by all visitors (baseline + treatment) in the same experiment
coframe_experiment_slug string Human-readable experiment name
coframe_variant_id string The specific variant (or holdout) assigned to this visitor
coframe_variant_slug string Human-readable variant name
coframe_user_token string Unique visitor identifier (persistent across visits)
coframe_impression_id string Unique ID for this specific page view / impression
coframe_in_global_holdout boolean true if the visitor is excluded from all experiments (Step 1 holdout)
coframe_in_exp_baseline boolean true if the visitor is in the experiment baseline (Step 2 holdout)

The TypeScript type for this payload:

TS
type CoframeTreatmentDataV2 = {
  coframe_experiment_id: string;
  coframe_experiment_slug: string;
  coframe_variant_id: string;
  coframe_variant_slug: string;
  coframe_user_token: string;
  coframe_impression_id: string;
  coframe_in_global_holdout: boolean;
  coframe_in_exp_baseline: boolean;
};

02How a Visitor Gets Assigned

Assignment follows a three-step gate. A visitor must pass each step to reach the next.

Step Gate Default split If passed
1. Global Holdout project-wide 5% holdout / 95% pass continue to Step 2
2. Experiment Holdout per-experiment e.g. 50% baseline / 50% treatment continue to Step 3
3. Variant Selection weighted traffic e.g. 33/33/34 across variants sees that variant

Each step is a gate — a visitor filtered out at any step never reaches the next.

Seats and iterations: By default a visitor’s seat changes hourly when a new experiment iteration begins; each new seat re-runs the assignment logic, so a visitor may enter or leave the treatment group between iterations. Sticky seats keep the same variant assignment for the duration of the experiment, regardless of iterations. The global-holdout seat is permanent for the lifetime of the project — a visitor placed in the global holdout stays there.

03Experiment Entity Hierarchy

The assignment model is a tree. Each level maps to one or more identifiers in the callback payload.

PLAINTEXT
Global Experiment            (coframe_experiment_id)
├─ Global Holdout            (coframe_in_global_holdout: true)
└─ Global Treatment          (coframe_in_global_holdout: false)
   └─ Frames                 (Home / Product / Cart …)
      └─ Audiences           (Global / Desktop / Mobile — each its own holdout experiment)
         └─ Experiment Holdout
            ├─ Baseline       (coframe_in_exp_baseline: true)
            └─ Treatment      (coframe_variant_id)
               └─ Experiment  (coframe_experiment_id)
                  └─ Variants  v0 / v1 / v2 / v3 (coframe_variant_id)

Level 1 — Global Experiment. A single top-level experiment that wraps the entire project. It controls the global holdout split: a small percentage of all visitors are assigned to the global holdout and see no Coframe experiments at all. Their presence allows clean-room measurement of Coframe’s aggregate effect on the site.

Level 2 — Frames. A frame is a named region of the page — for example, homepage-hero, product-description, or checkout-cta. Frames are the units of experimentation. Each frame can run one active experiment at a time for any given visitor.

Level 3 — Audiences. Within a frame, each audience (Global, Desktop, Mobile, or a custom segment) runs as its own sub-experiment. A visitor is matched to the first audience whose targeting conditions they satisfy. Unmatched visitors skip the frame entirely.

Level 4 — Experiment Holdout. Once an audience is matched, the visitor enters the experiment holdout step. This is a per-experiment split that separates the baseline group (visitors who see the original content but are tracked for comparison) from the treatment group (visitors eligible to see a variant). The coframe_in_exp_baseline field reflects this split.

Level 5 — Experiment. The experiment is the container for a set of variants running against the baseline. Baseline and all treatment visitors share the same coframe_experiment_id, which is what makes cross-group comparison possible.

Level 6 — Variant Selection. Treatment-eligible visitors are assigned to a specific variant. The coframe_variant_id identifies the assigned variant. Traffic can be split evenly or with custom weights across any number of variants.

04Frames with Multiple Experiments

A frame can have multiple experiments configured, each targeting a different audience. When a visitor arrives, Coframe evaluates the audiences in order and stops at the first match. Only one experiment per frame activates for any single visitor.

Visitor Exp1 (Desktop) Exp2 (Mobile) Result
Desktop user Matches Skipped Enters Exp1’s holdout/variant tree
Mobile user Doesn’t match Matches Enters Exp2’s holdout/variant tree
Tablet user Doesn’t match Doesn’t match No experiment activates

Four rules govern this behavior:

  • Each experiment targets exactly one audience.
  • The first matching audience wins; subsequent audiences are not evaluated.
  • Only one experiment per frame activates per visitor per page view.
  • Parallel experimentation is possible across different frames simultaneously, but not within a single frame.

05How Baseline and Treatment Visitors Are Grouped

Both baseline and treatment visitors share the same coframe_experiment_id. This is intentional — it allows them to be analyzed together in the same experiment report. Use coframe_variant_id and coframe_in_exp_baseline to tell them apart.

Visitor group coframe_experiment_id coframe_variant_id coframe_in_exp_baseline
Baseline abc...01 abc...02 (baseline variant) true
Treatment — Variant A abc...01 def...05 false
Treatment — Variant B abc...01 def...06 false
Global Holdout zzz...99 (holdout experiment) zzz...98 false

The global holdout is not part of the experiment, so its coframe_experiment_id is different from the one shared by baseline and treatment visitors.

06Callback Examples

The following examples show the exact payload shape for the three visitor outcomes.

Visitor 1 — Treatment (sees Variant A): passed both holdouts, assigned to Variant A.

JSON
{
  "coframe_experiment_id": "abc...01",
  "coframe_experiment_slug": "homepage-headline",
  "coframe_variant_id": "def...05",
  "coframe_variant_slug": "homepage-headline-v1",
  "coframe_user_token": "usr_a1b2c3",
  "coframe_impression_id": "imp_x1y2z3",
  "coframe_in_global_holdout": false,
  "coframe_in_exp_baseline": false
}

Visitor 2 — Baseline: sees the original page and is tracked for comparison.

JSON
{
  "coframe_experiment_id": "abc...01",
  "coframe_experiment_slug": "homepage-headline",
  "coframe_variant_id": "abc...02",
  "coframe_variant_slug": "homepage-headline",
  "coframe_user_token": "usr_d4e5f6",
  "coframe_impression_id": "imp_a7b8c9",
  "coframe_in_global_holdout": false,
  "coframe_in_exp_baseline": true
}

Visitor 3 — Global Holdout: excluded from all experiments. Note the different coframe_experiment_id — it identifies the global holdout group, not the homepage-headline experiment.

JSON
{
  "coframe_experiment_id": "zzz...99",
  "coframe_experiment_slug": "global-holdout",
  "coframe_variant_id": "zzz...98",
  "coframe_variant_slug": "global-holdout",
  "coframe_user_token": "usr_g7h8i9",
  "coframe_impression_id": "imp_d1e2f3",
  "coframe_in_global_holdout": true,
  "coframe_in_exp_baseline": false
}

Key observations: Visitors 1 and 2 share the same coframe_experiment_id (abc...01), which groups baseline and treatment together for analysis. Visitor 3 has a different coframe_experiment_id (zzz...99) because they were excluded before reaching any experiment.

07Dashboard vs. Callback IDs

In the Coframe dashboard, baseline and treatment variants appear side by side in the same experiment report. They are unified by their shared coframe_experiment_id. This is why the dashboard can show baseline conversion rates alongside each treatment variant — they all belong to the same experiment container.

The key distinction is that baseline and treatment are assigned at different steps in the gate logic (Step 2 vs. Step 3), but both are captured under the same coframe_experiment_id. When connecting Coframe data to an external analytics tool, always use coframe_experiment_id from the callback as the primary grouping key. Do not attempt to reconstruct experiment membership from coframe_variant_id alone, because that field identifies the specific variant, not the experiment as a whole.

08Using Callback Data in Analytics

When forwarding treatmentsDataV2 data to an external analytics platform:

  • Group visitors by coframe_experiment_id to assemble the full experiment population (baseline + all treatment variants).
  • Identify which variant each visitor saw using coframe_variant_id and coframe_variant_slug.
  • Separate the baseline group from treatment groups using coframe_in_exp_baseline: true.
  • Identify visitors excluded from all experiments using coframe_in_global_holdout: true; they can be used for a clean holdout comparison.
  • Use coframe_user_token for visitor-level attribution and cross-session stitching.
  • Use coframe_impression_id for impression-level deduplication when the same visitor sees the same experiment on multiple page views.

09Summary

Concept Key point
3-step assignment Global holdout → experiment holdout → variant selection. Each step is a gate; visitors who don’t pass are not assigned downstream.
coframe_experiment_id Shared by all visitors in the same experiment, including baseline. Use it to group populations for analysis.
Multiple experiments per frame Targeting is audience-based; only the first matching audience’s experiment activates per visitor per frame.
Deterministic assignment A visitor’s seat is determined by a hash of their coframe_user_token, so the same visitor always lands in the same bucket within an iteration.

Content and video lessons from Coframe documentation. Code examples are not executed on this page.

BACK TOCore Concept

Documentation

Open Coframe App

Search documentation

Search all guides and references↑ ↓ Navigate · Esc Close