Skip to content
ver
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);
  },
};