← Back to all work
Screwfix Optimizely Edge Large UK home improvement retailer

Add-to-bag interstitial CTA

When a product is added to the bag, an interstitial overlay appears with a primary CTA. This test relabelled that CTA to match what users actually want at that moment, and instrumented the entire add-to-bag journey across PLP and PDP on the live Next.js storefront.

The problem

The add-to-bag interstitial led with "Checkout Now". At the moment a user has just added one item, that label asks for a bigger commitment than most are ready to make: they want to see the bag, not start paying. The wording and the intent were mismatched, and progression from the overlay was leaking.

An earlier test had redesigned this overlay and lifted basket-CTA clicks by +12.61%, but it changed layout, messaging and copy all at once, so the gain couldn't be pinned to any single change. This test isolates one variable, the CTA label, and measures it on its own.

The hypothesis

If we relabel the interstitial CTA from "Checkout Now" to "Go to Basket", then more users will progress from the add-to-bag overlay, because the label now matches the action they actually want at that step.

The solution

A one-line copy change on the surface, but a non-trivial build underneath. The storefront is a Next.js / React single-page app: the interstitial mounts asynchronously after the add-to-bag request resolves, the DOM hydrates in stages, and the whole flow has to survive client-side route changes. The variation swaps the CTA text once the overlay has rendered, and instruments every meaningful step of the journey to GA4 and Optimizely so the decision rests on clean data.

Control versus Variant of the add-to-bag interstitial: Control's primary CTA reads Checkout Now, the Variant reads Go to Basket
Control (left) led with "Checkout Now"; the variant (right) relabels the same primary button to "Go to Basket". Everything else on the overlay is unchanged.

Implementation

The build is event-delegated from document.body, so it keeps working as React re-renders cards and overlays. On add-to-bag it waits for the host's loader to clear before reading the interstitial, captures the fulfilment type (Click & Collect vs Delivery) and page type, then re-runs the relabel.

// Swap the interstitial CTA once it has rendered

const NEW_BTN_TEXT = 'Go to Basket';
const checkoutNowBtns = document.querySelectorAll('[data-qaid="button-checkout-now"]');

checkoutNowBtns.forEach((btn) => {
  const span = btn.querySelector('span');
  // only relabel the genuine "checkout" CTA, never anything else
  if (span && /checkout/i.test(span.textContent)) {
    btn.setAttribute('title', NEW_BTN_TEXT);
    span.textContent = NEW_BTN_TEXT;
  }
});

Waiting for the overlay, then measuring it

The interstitial doesn't exist at click time. The handler adds a state class, polls until the loader spinner is gone, fires the add-to-bag event tagged by fulfilment type and page, then re-runs init() to relabel the now-rendered CTA and log the overlay impression.

document.documentElement.classList.add(`${ID}-atc`);

setTimeout(() => {
  pollerLite([() => !document.querySelector('[data-qaid="loader"]')], () => {
    const channel = fulfilmentType.includes('Collect') ? 'C&C' : 'Delivery';
    fireEvent(`User adds ${channel} product to bag from ${pageType()}`);
    trackOptimizelyEvent(`User adds ${channel} product to bag from ${pageType()}`);

    setTimeout(() => {
      init(); // overlay is in the DOM now, relabel the CTA
      fireEvent(`Add to bag pop up Impression (${pageType()})`);
    }, 200);
  });
}, 500);

SPA-aware, fires once per navigation

On every client-side route change the experiment re-arms against the Tealium and Next.js data layers, resetting per-page state so the quantity-stepper tracking and the relabel both stay correct as the user moves between listers and product pages without a full reload.

onUrlChange(() => {
  pollerLite([
    () => typeof window.tealiumDataLayer === 'object',
    () => window.utag !== undefined,
    () => window.__NEXT_DATA__ !== undefined,
  ], () => {
    lastQty = null; // reset stepper state for the new page
    document.documentElement.classList.remove(`${ID}-atc`);
  });
});

Instrumentation

Beyond the relabel, the test logs the full overlay journey to GA4 and Optimizely in parallel: add-to-bag by fulfilment type and page, quantity-stepper increases, overlay impressions, "continue shopping" clicks, the relabelled "Go to Basket" clicks, and every way the user can dismiss the modal (X button, overlay click, or away-navigation). The agency's experiment ID is appended to window.brainLabsExperimentID for cross-platform attribution.

Success metrics

Primary: conversion rate and add-to-bag rate. Secondary: progression from the interstitial, "Go to Basket" vs "continue shopping" split, and dismissal rate by method.

Post-test analysis

Winning variant, shipped to 100%. Across 16 days and roughly 186,000 users, relabelling the single CTA lifted conversion rate +10.04% and add-to-bag +14.47%, with no negative signal on any KPI. In-test revenue contribution was £26,696, an annualised potential of £9.84m.

MetricControlVariantUplift
Conversion rate26.18%28.81%+10.04%
Add-to-bag rate43.85%50.19%+14.47%
Purchaser rate52.52%53.09%+1.09%
Average order value£44.77£44.90+0.29%
Revenue per user£32.90£33.55+1.97%

The result held on both devices: mobile conversion rate +7.66% (revenue per user +4.60%), desktop conversion rate +9.36% (add-to-bag +13.95%). The softer label worked regardless of where the user was shopping.

Because the build instrumented the CTA at both page types, the funnel movement was visible directly: "Go to Basket" clicks rose +16.46% on listers and +10.11% on product pages, while "continue shopping" clicks fell. The label pulled browsing intent forward into the basket rather than back into the catalogue, and the rise in purchaser rate confirmed those were higher-intent entries that went on to convert, not just extra basket visits.

The recommendation was unambiguous: ship "Go to Basket" as the default interstitial CTA across all devices. One isolated word of copy, measured cleanly, carrying a £9.84m annualised potential.

← Back to all work