Selected experiments showing the kinds of problems I solve: SPA-aware
UI, server-load mitigation, enterprise platform quirks, and accessibility-compliant
variants.
Desktop search immersive UI
Large UK home improvement retailer
Vertical search overlay had low engagement. F-pattern
reading suggested a landscape layout could lift SRP progression.
Built a darkened focus-state overlay, repositioned the
search element to a landscape layout, and added search-term-driven subcategory
chips for Variant 2. Maintained existing product-suggestion logic to isolate
layout as the variable. Two variants shipped sitewide on desktop.
Read the case study →
Sample Ratio Mismatch in SPA experiments
Why your GA4 split never matches the platform
GA4 shows 60:40 when the testing platform shows 50:50.
Random, unstable, never matches, and the experiment code is rarely the
actual cause.
Walks through the four root causes of GA4/platform Sample
Ratio Mismatch on SPAs (data layer timing, beacon loss, virtual pageview
context, bot traffic) and the Tealium/GTM tracking pattern (with
utag.link intercept and payload mirroring) that fixes most of
them.
Read the article →
Quote-step redesign on a React funnel
UK vehicle scrappage and valuation service
A revenue-critical Vehicle Details step, redesigned to a
cleaner single column with the offer in a banner, delivered client-side through
Convert on a React single-page app with no access to the codebase.
Re-skinned React's own form rather than rebuilding it: CSS
for everything it can do so it survives re-renders, JavaScript only for the
banner, icon and CTA, kept idempotent and re-applied across the funnel's route
changes, with the vehicle read live from localStorage. Built and in QA.
Read the case study →
Article
Tooling
I built a CRO build tool
abtestrig, a CRO-specific build tool, open source on
GitHub
Every CRO dev rebuilds the same Gulp/webpack rig.
Hardcoded loader-script IDs, 8 to 15s rebuilds, page reloads on every CSS tweak,
and no way to test interactions between two live experiments before
shipping.
Built abtestrig around esbuild: sub-200ms builds, a loader
that auto-discovers the active experiment and port (no script edits between
experiments), CSS hot-swap via a stable <style> slot so
the activated state is preserved, stack-mode that runs multiple experiments
in deterministic order for conflict testing, and a shared @lib
helper library so pollerLite/waitForElement stop
getting copy-pasted between projects.
Read the article →
HubSpot CMS landing page build
UK ground engineering / residential subsidence
Geobear runs a HubSpot CMS estate of 50+ pages across several
brand variants, all powered by the same theme. The brief: a new residential
landing page with a different layout and modules, without putting the 50+ live
pages at risk.
Cloned the live theme into a parallel build via
hs cms fetch / hs cms upload, then shipped nine custom
modules from scratch: sticky nav, hero with background video, case carousel,
get-advice flow, logos, testimonials, video gallery, CTA banner, and a Leadoo
form wrapper. Deferred Swiper init via IntersectionObserver, a
ResizeObserver shim for sticky-nav padding under HubSpot's
overflow: hidden wrappers, CSS custom properties for the design
system, and inline schema.org JSON-LD (HowTo,
ItemList, Review) that passed the Rich Results
Test.
Read the case study →
"Shop Similar" follow-me carousel
Large UK home improvement retailer
Google Shopping landers were exiting PDPs and re-entering
through Shopping multiple times when the specific product didn't fit. Top-50
power-tool SKUs by click volume were the priority.
Built a sticky "follow-me" similar-products carousel
scoped to the product's category. Scrapes the breadcrumb-derived PLP at a
price-bound API call, caches results in sessionStorage so
subsequent PDPs in the same category render instantly. V2 layers a brand
filter for brand-loyal users.
Read the case study →