<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/css/simple-atom.xslt"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Death.au's Domain posts tagged Analytics</title>
  <subtitle>Thoughts, stories and ideas.</subtitle>
  <link rel="self" href="https://death.id.au/tag/analytics/atom.xml" type="application/atom+xml" />
  <updated>2026-08-05T06:30:37Z</updated>
  <author>
    <name>Death.au</name>
  </author>
  
  <id>https://death.id.au/tag/analytics/</id>

  
  <entry>
    <title>Canvas Factory</title>
    <id>https://death.id.au/cv.22/</id>
    <updated>2026-06-12T00:00:00Z</updated>
    <published>2026-06-12T00:00:00Z</published>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><h1>Canvas Factory</h1>
<p>Canvas Factory print wall art — you pick an image, pick a size, and they print and ship
it. They run CS-Cart across Australian, New Zealand and US storefronts, and I was
brought in to implement GA4 and Google Tag Manager ecommerce tracking across all of it.</p>
<p>Which sounds routine, and wasn't, because of one structural fact: <strong>the store doesn't
sell products.</strong></p>
<h2>Selling sizes, not products</h2>
<p>The images come from external licensing providers — Getty, Alamy and others — at a scale
approaching 100,000 images. They aren't CS-Cart products. They don't have product IDs,
they aren't in the catalogue, and they can't be, because the catalogue would be
meaningless at that size and would need to track someone else's inventory.</p>
<p>What the store actually sells is a <em>size of a print of an image</em>. GA4's ecommerce model,
meanwhile, very much wants a product with an ID and a category. So the job became
designing a mapping: a composite item-ID scheme of <code>{source}_{art_image_id}</code> that stays
stable across sessions and providers, and a category hierarchy that GA4 would accept and
that the client's marketing team could actually read in a report.</p>
<h2>Two bugs worth mentioning</h2>
<p><strong>An <code>add_to_cart</code> event that had never once fired in production.</strong> The listener existed
on the upgraded site, so it worked in every environment anyone tested in. It was missing
entirely from live. Nobody had noticed, because the absence of an event doesn't look
like anything — the reports just quietly had a hole where the most important step of the
funnel should be.</p>
<p><strong>Event integrity across an iframe boundary.</strong> The canvas configurator — where the
customer crops and positions their image — is an iframe maintained by a third-party
developer, so events had to cross a <code>postMessage</code> handoff between two codebases, only
one of which I controlled. Debugging that meant establishing, for each event, whether it
was fired at all, fired twice, fired with the wrong payload, or fired into a listener
that had already been torn down. It's a good reminder that in analytics work the bug is
almost never in the analytics.</p>
<p>All of the tracking work shipped, and the client and marketing company involved were
very happy with the results.</p>
</div></content>
    <link rel="alternate" href="https://death.id.au/cv.22/" />
    <summary type="html">Ecommerce analytics for a store that doesn&#39;t sell products — it sells sizes.</summary>
  </entry>

</feed>