AB Designer42 liveDemo
Live demo · ship revenue, not guesses: cookieless A/B at the edge with real significance. Join the waitlist →
New experiment
Pricing headline
/pricing+41% upliftsignificant · 96% confidenceactive
variantsplitvisitorsconversionsratelift
Control50%1,980572.9%—
Value-firstwinning50%1,974804.1%+41%
CTA button copy
/+7% upliftnot yet significantactive
variantsplitvisitorsconversionsratelift
Get started50%4,1201734.2%—
Start freewinning50%4,1801884.5%+7%
Hero layout
/-2% upliftnot yet significantpaused
variantsplitvisitorsconversionsratelift
Control50%4,2101774.2%—
Split hero50%4,1881724.1%-2%
▸Deploy at the edge
Deploy this Cloudflare Worker on your zone to apply variants at the edge — swap YOUR_SITE_TOKEN for your tracker token.
export default {
async fetch(req, env, ctx) {
const res = await fetch(req);
if (!(res.headers.get('content-type') || '').includes('text/html')) return res;
const url = new URL(req.url);
const cfg = await fetch(
'https://getvero.dev/api/experiments/config?s=YOUR_SITE_TOKEN',
{ cf: { cacheTtl: 60 } },
).then((r) => r.json()).catch(() => ({ experiments: [] }));
const exp = cfg.experiments.find((e) => e.path === url.pathname);
if (!exp) return res;
// cookieless sticky bucket from IP + UA
const id = (req.headers.get('cf-connecting-ip') || '') + (req.headers.get('user-agent') || '');
const bucket = [...id].reduce((a, c) => (a * 31 + c.charCodeAt(0)) % 100, 7);
let acc = 0;
const variant = exp.variants.find((v) => (acc += v.weight) > bucket) || exp.variants[0];
// Apply the variant AND stamp a marker so the Vero tracker's experiments
// module can record the exposure that matches what was actually served.
const rw = variant.changes.reduce(
(r, ch) => r.on(ch.selector, {
element(el) { el.setInnerContent(ch.html, { html: true }); },
}),
new HTMLRewriter().on('head', {
element(el) {
el.append('<meta name="vero-exp" content="' + exp.key + ':' + variant.key + '">', { html: true });
},
}),
);
return rw.transform(res);
},
};