Case study · Shopify CRO
A CRO audit, built on a live storebefore Spring Racing.
A Sydney milliner sells more than 500 styles of designer headwear online. An outside CRO expert wrote the audit. I was hired to build it, with the first five fixes due within a week.
ClientDesigner milliner, Sydney
RoleCRO implementation, plus search, catalog, and SEO fixes
StackShopify, Liquid, JavaScript, reviews app, structured data
SHIPPING RECEIPT
Sydney milliner
Cart pop-up to checkoutdone
Sizing & Fit for headweardone
Cross-sells auto-filleddone
Breadcrumbs with schemadone
Clicks to pay4 → 2
Fixes shipped4 of 4
SHIPPEDShipped
The audit, built.
Each recommendation from the audit, with what changed and where it stands.
| # | Recommendation | What changed | Status |
|---|---|---|---|
| 01 | Cart pop-up straight to checkout | Button reads CHECKOUT; the cart page detour is gone | done |
| 02 | Reassurance at the buy button | Free returns, plus the made-in-Australia claim the client confirmed | done |
| 03 | Sizing for headwear | S 54 to 55 cm through XL 60 to 61 cm, replacing a face-mask chart | done |
| 04 | Product reviews | Review requests that link to the product bought | done |
| 05 | Homepage testimonials | Matching the section shoppers see on product pages | done |
| 07 | Cross-sells | Fill in automatically when a product has none set | done |
| 09 | Homepage categories | Fascinators, Sun Hats, Race Day, Headbands, Earrings, Bags | done |
| 10 | Breadcrumbs | On collection and product pages, with structured data | done |
| + | Collection swatches | One card per style, colours as swatches | in review |
Try the two biggest changes
Fewer steps to pay. Every colour in one card.
The cart pop-up
2clicks from add-to-cart to paying
Add to cartPop-upCHECKOUT
Under the button: free returns, and the made-in-Australia claim the client confirmed.Collection swatches
in reviewONE STYLEWhite · 1 of 11
One card per style, colours in a single row with arrows, as the client asked. Colours shown are illustrative.
Under the hood
The snippet behind the swatches.
{%- comment -%} One card per style, colours as swatches {%- endcomment -%}
{%- assign style = product.metafields.custom.style.value -%}
<div class="style-card" data-style="{{ style.handle }}">
{%- for colour in style.colours.value -%}
<a class="swatch" href="{{ colour.product.value.url }}"
style="--swatch: {{ colour.hex }}"
aria-label="{{ colour.name }}"></a>
{%- endfor -%}
</div>
snippets/style-card.liquid
1Styles live in a metaobject, so a hat sold in dozens of colours becomes one card instead of dozens.
2Every swatch is a real link, so Google still reaches and ranks each colour page.
3Screen readers hear the colour name, not “link”.
Simplified for reading. Client names and data removed.
Beyond the audit
Found by digging, not guessing.
| Found | Number | What I did |
|---|---|---|
| Draft products invisible to every filter | hundreds | A tagging plan for new arrivals: category, occasion, colour, hat style |
| Search that didn’t narrow anything | ~92% | Traced it to related-product matching and added category shortcuts |
| Tracking tags blocked by one speed app | 3 | Flagged that GA4, Google Ads, and the Meta pixel weren’t loading |
| Internal pages showing in Google | 2 | Hidden and marked no-index, plus article schema on every blog post |
Training provider