Growth

Conversion and analytics for online stores

A/B tests that survive caching, honest analytics, search, reviews and shoppable media.

10 guides10 in-depth132 min of reading

Most conversion tools are added as a script in the browser, and that one choice causes most of their problems. An A/B test that rewrites the page after it loads makes the page flicker, or hides it until the script runs. A review or video widget loads hundreds of kilobytes from third parties and shifts the layout when it arrives. An analytics pixel is blocked by ad blockers and limited by Safari, so the numbers used to judge every change are incomplete. The guides in this topic move each of these decisions to the server or to build time, where the HTML can be correct before it reaches the shopper and measurement doesn't depend on a script surviving the browser.

Server-side A/B testing on WooCommerce picks the variation in a Cloudflare Worker before the HTML exists and puts the decision in the URL. Every cache keeps one entry per variation rather than one per visitor, and in our test 200 new visitors split 110/90 with no flicker. A/B testing a headless Next.js store prerenders each variation and lets the proxy choose. One shared SDK client cost 0.4 ms per request in our test, against 158 ms when a new client was created for each request. Fathom vs GA4 found that even a cookieless script is blocked by privacy filter lists, so purchases are best recorded from the order itself. Server-side ad tracking applies the same idea to Meta and TikTok, with hashed customer data and a shared event ID to avoid double counting.

The rest of the topic covers what shoppers see. Server-rendered Loox reviews and server-rendered EmbedSocial reviews put review text into the HTML. In our test the EmbedSocial widget added 965 KB over 25 requests, while the server-rendered version added 1.6 KB of markup. Shoppable video reserves the player's space and loads video only on tap. Zero-result searches turns failed searches into synonyms and redirects. KPI dashboards builds one row of numbers per day the same way every day, so changes can be measured.

Start here

Conversion & analytics15 min read

Server-side A/B testing in WooCommerce: no flicker, and the page cache still works

Client-side testing tools flicker because the cached page arrives first and a script rewrites it afterwards, or hide the page until the script runs. To avoid both, pick the variation before the HTML exists. A Cloudflare Worker running Convert's JavaScript SDK reads the visitor's cookie, buckets them with Convert's deterministic hash, and adds the decision to the origin URL as ?_ab=experience.variation. A small WordPress plugin then renders only that variation's block. Because the decision is in the URL, every cache in between keeps one entry per variation instead of one per visitor. In our test on a real WooCommerce store, 200 new visitors split 110/90 and each variation was rendered by WordPress once; every other request was a cache hit. A cached variation came back in a median 42 to 78 ms across three runs, against 0.6 to 2.4 seconds for an origin render. Conversions are sent from the order-received page, once per order. Convert is our pick; its Full Stack SDK is on the Pro plan.

Conversion & analytics14 min read

Privacy-first WooCommerce analytics: server-side purchase tracking with Fathom vs GA4

GA4 sets cookies, so in the EU and UK it needs consent before it runs, and its scripts are on the main ad-blocker lists. Fathom Analytics sets no cookies (Fathom says no cookie banner is needed for it) and its script is about 2 KB, against about 150 KB for gtag.js. But a privacy-first tool isn't block-proof: when we ran the EasyPrivacy and uBlock privacy lists through Brave's filter engine, Fathom's script and event beacon were blocked just like GA4's. Fathom also has no API for sending events from a server, so the purchase event still comes from the browser. The reliable setup is therefore two-sided: a small mu-plugin sends one Fathom Purchase event per paid order from the thank-you page, and a WooCommerce order webhook feeds a server-side ledger that no ad blocker can touch. A reconcile command then compares the two through Fathom's API and tells you what share of orders and revenue the browser missed. Fathom is our pick for cookieless traffic and conversion analytics; GA4's Measurement Protocol does take server-side events, but it needs the visitor's GA client ID from a cookie, so consent still applies.

Conversion & analytics15 min read

Headless Shopify reviews: fetching Loox photo and video reviews without ruining LCP

On a headless Shopify store, skip the Loox script widget on product pages and render reviews on the server from the Loox Storefront API. The API is public (no key; you pass your public store ID), returns published reviews with photo and video URLs, and has a bottomline endpoint with the review count and average rating. Called from a Next.js server component it answered without an Origin header, while a browser on a domain Loox doesn't know got 403. Render the review text into the HTML, resize the 500 KB+ original photos through the image optimizer, show video reviews as a thumbnail until the shopper clicks, and print one Product JSON-LD block whose aggregateRating comes from the same bottomline the page shows. In our lab test the server-rendered page weighed 223 KB, against 1.8 MB with the same media loaded eagerly. The official widget couldn't render on our test domain at all: its review iframe only loads on domains you allow-list, which needs Loox's Convert plan. Loox is our pick for photo and video reviews on Shopify; Yotpo fits enterprise brands that want reviews, loyalty and SMS from one vendor.

All conversion & analytics guides

Conversion & analytics13 min read

Shoppable lookbooks and B2B catalogs in WooCommerce: hotspots as JSON post meta, without a SaaS script

Store all of an image's or video's hotspots in one JSON post meta row on the media file, with x and y as percentages of its width and height, and render them as positioned HTML details elements. Percentages keep each hotspot on the same point at any screen size; in our test they were within 0.01% of the stored point at 390 px and 1280 px wide. Load every tagged product with one wc_get_products() call: for 12 hotspots that took 14 database queries on a cold cache, against 42 when each hotspot loaded its own product. Products that are deleted, drafted or hidden since they were tagged simply don't appear. On phones, the product card opens as a bottom sheet so it never covers the other hotspots. A SaaS platform such as Taggbox is the better choice when the content is customer photos and social posts rather than your own catalog shots.

Conversion & analytics16 min read

Shoppable video in a headless store: a light API component vs a third-party widget iframe

A shoppable video widget hurts Core Web Vitals in two ways. If its box has no height until the widget loads, it pushes the page down (CLS). And if it autoplays a preview, it spends the shopper's bandwidth on video before they've asked for it. In our test on a throttled phone profile, an iframe widget without reserved space scored a CLS of 0.069 on every run and downloaded about 3.3 MB of video in the first seven seconds. Giving the same widget a CSS-sized slot brought CLS to 0, but it still downloaded the video. A small web component that reserves its height in CSS, fetches a JSON feed only when the rail nears the screen, and creates the video element only on tap had a CLS of 0, downloaded no video before a tap, and loaded 284 KB in total. If you use a hosted platform such as Tolstoy for tagging, analytics and UGC collection, give its widget a fixed-height slot and inject its script when that slot approaches the viewport.

Conversion & analytics14 min read

A/B testing a headless Next.js store: proxy routing vs static generation

You don't have to choose between them. Prerender every variation as its own static page (app/pdp/[variant]/[handle], with generateStaticParams and revalidate), and let Next.js's proxy (called middleware before Next.js 16) pick the variation per visitor and rewrite /products/mug to /pdp/b/mug. The page stays static, there's no client-side swap and no flicker. Ask VWO's SDK once per visitor and keep the answer in a cookie: getFlag() sends an impression every time it's called, and the proxy can't tell a prefetch from a page view. Create one VWO client per server and reuse it: init() downloads the settings file, which cost 158 ms per request in our test against 0.4 ms for a shared client. Two production traps we hit: the rewritten response still says s-maxage=3600 under the public URL, so a URL-keyed CDN would serve one variant to everyone, and Next.js runs the proxy again for the rewritten path if the matcher covers it. VWO (now part of Wingify) is our pick.

Conversion & analytics12 min read

Server-side rendering WooCommerce social proof: EmbedSocial's API vs client-side widgets

A JavaScript review widget puts your Google reviews in an iframe, not in your product page: with EmbedSocial's own demo widget, none of the review text was in the server HTML or the page's own document, and the widget added 965 KB over 25 third-party requests (scripts for YouTube and Vimeo, avatars and EmbedSocial's frame). Reading the same content from the EmbedSocial API on the server and printing it as HTML adds 1.6 KB of markup and only lazy-loaded images. Cache it in a WordPress transient, keep a last-good copy in an option, and refresh it in WP-Cron so no shopper ever waits for the API. Show the newest reviews whatever their rating, label them as reviews of the store, and keep them out of structured data: Google Business reviews are about your business, not the product, and Google's rules say not to aggregate ratings from other websites. The product's AggregateRating should come only from WooCommerce's own product reviews. EmbedSocial is our pick (its API is on the Premium plan); Taggbox is a strong alternative for shoppable UGC galleries.

Conversion & analytics14 min read

Automating e-commerce KPI dashboards: Databox vs custom Python and Google Sheets

A KPI dashboard that managers trust needs one row of numbers per day, built the same way every day, from WooCommerce orders, Stripe subscriptions and Search Console. A Python script on cron can pull all three APIs, join them on customer email and write the row to a Google Sheet for free. It's the only way to get cross-source metrics such as LTV that includes store purchases, but you own every token, API change and silent failure. Databox connects WooCommerce, Stripe and Search Console natively, syncs hourly on paid plans, and adds goals, alerts and scheduled reports, so day-to-day maintenance drops to near zero. The best setup combines them: Databox's connectors for standard metrics, plus a small nightly script that pushes the custom metrics (MRR, 30-day churn, LTV, subscriber store revenue) into a Databox dataset through its v2 API. Our tested script does both, rewrites the last four days because Search Console data arrives late, and can write the same rows to Google Sheets. Databox is our pick; Metabase and Grafana are the open-source alternatives if you'd rather host it yourself.

Conversion & analytics15 min read

Shopify zero-result searches: find the missed revenue with ShopifyQL, fix it natively, or hand it to Searchanise

Shopify records every online store search with a search_results_were_returned flag, and since Admin API 2025-10 you can query it with ShopifyQL (FROM searches, read_reports scope). Pull the zero-result queries monthly, compare their words against your catalog's own vocabulary, and sort them: typos and missing synonyms go into the Search & Discovery app, combinations need merchandising, true gaps are a stocking or redirect decision. The script in this guide does the sorting and publishes reviewed redirects to a shop metafield your theme reads. If you'd rather not maintain that loop, Searchanise handles synonyms, typo suggestions, search redirects and no-result analytics as one app, from $16 a month billed yearly for up to 1,500 products.

Conversion & analytics4 min read

Why Meta and TikTok pixel attribution under-reports, and how server-side events fix it

Browser pixels now miss many conversions because of Apple's App Tracking Transparency, Safari's cookie limits, link-parameter stripping and ad blockers. Server-side tracking sends the same purchase events from your store's server through Meta's Conversions API or TikTok's Events API, with hashed customer data and a shared event ID to prevent double counting.

Tools these guides recommend

Disclosure: these are affiliate links. If you sign up through them, I may earn a commission at no extra cost to you. How this site makes money.

More in growth