Variations
Variation numbering
Generated numeric variations are numbered from 1. In a standard A/B test:
v1- control (no change, or baseline treatment)v2- treatment Av3- treatment B (A/B/C test)
The framework also supports a dedicated named control entry:
pnpm new-variation controlThis creates src/js/control/index.jsx from v1. Numeric folders are always ordered before named folders, so v1, v2, and control build in that order.
Adding a variation
The scaffolder generates v1 and any additional variations you requested. To add another variation later, use the generated command:
pnpm new-variation 3
pnpm new-variation controlThese commands create src/js/v3/index.jsx or src/js/control/index.jsx from v1. They also copy src/js/v1/styles.module.scss when present; the current scaffold uses this file for mount-root styling.
After creation, open src/js/v3/index.jsx and update:
- The tracking label, for example
my-experiment: v3 cta clicked. - Any selectors, props, component logic, or styles specific to this variation.
Build to confirm the new variation compiles:
pnpm build
# dist/v1-index.jsx
# dist/v2-index.jsx
# dist/v3-index.jsxDeveloping a specific variation
pnpm start 0 # variation 1 (src/js/v1/)
pnpm start 1 # variation 2 (src/js/v2/)
pnpm start 2 # variation 3 (src/js/v3/)The index is always zero-based and follows discovered build order. Numeric folders come first, followed by named folders such as control.
For example, with only v1 and control, run:
pnpm start 1 # src/js/control/pnpm start N watches one variation. Restart it with a different index to switch variations.
Production build
pnpm buildBuilds all variations in parallel. Output:
dist/
├── v1-index.jsx
├── v2-index.jsx
├── vN-index.jsx
└── control-index.jsxBiome runs before the build. The build aborts if linting fails.
Prevent duplicate mounts
Adobe Target may run custom code again after an SPA route change. Because mountExperiment does not check for an existing instance, add a guard before mounting on SPA pages:
import style from './styles.module.scss';
runScript(async () => {
const marker = 'my-experiment-v1';
if (document.querySelector(`[data-experiment="${marker}"]`)) return;
const container = mountExperiment(selectors.primary, selectors.fallbacks, 'afterbegin', {
className: style.root,
dataset: { experiment: marker },
});
if (!container) return;
render(<MyComponent />, container);
setupTracking(container, { label: 'my-experiment: v1 cta clicked' });
});Set the marker immediately after mounting so subsequent runs hit the guard.
SPA pages
If you omit the dedup guard on an SPA, the component will mount multiple times on navigation. Add it whenever the target page uses client-side routing.