Files
mozimo.in/docs/analytics-setup.md
T
2026-09-06 16:34:23 +00:00

7.2 KiB

Analytics Setup — mozimo.in

The site ships with a layered, code-complete analytics stack. This document covers the dashboards you must create and the steps only you can do; after them, everything works with no further code changes.

Visitor browser
  ├─ gtag.js (GA4) ───────────────► GA4 property (consent-mode v2 gated)
  ├─ /stats/js/script.js ─┐
  └─ events /stats/api/event ── Caddy ──► Vince container (first-party)
Server (SSR) ── errors ──────────► Sentry
Shopify (shop.mozimo.in) ─ purchase/checkout ──► same GA4 property

1. What is already wired in code

Layer Implementation
GA4 Direct gtag.js injected in src/app/__root.tsx head scripts (production only, when VITE_GA4_MEASUREMENT_ID is set at build). send_page_view: false + PageViewTracker = exactly one page_view per navigation. Cross-domain linker to shop.mozimo.in.
Consent Google Consent Mode v2: denied-by-default in EU/EEA/UK/CH, granted elsewhere. ConsentBanner shows only to those visitors (timezone-detected, cookie-stored choice, /privacy explains everything).
First-party layer Vince (Plausible protocol), self-hosted via ansible/roles/analytics, proxied same-origin at /stats/* by Caddy — survives ad blockers, needs no consent.
E-commerce events view_item_list, select_item, view_item, begin_checkout, search, generate_lead (forms — no PII), click/contact (all outbound/tel/mailto links via src/components/Link.tsx), video_start, page_not_found, web_vitals. purchase is NOT hand-coded — Shopify reports it (step 2.2).
Errors Sentry client + server (custom entries src/client.tsx / src/server.ts), off unless DSN set.

2. One-time dashboards (manual)

2.1 GA4 property

  1. analytics.google.com → Admin → Create property (mozimo.in), currency INR, timezone India.
  2. Add a Web data stream for https://mozimo.in → copy the Measurement ID (G-…).
  3. Put it in your local .env as VITE_GA4_MEASUREMENT_ID=G-… (it is baked into the bundle at docker build by the Makefile).
  4. Data retention: Admin → Data settings → set 14 months.
  5. Data filters: add your office IP as Internal Traffic (defined filter).
  6. Cross-domain: Data stream → Configure tag settings → Configure your domains → add shop.mozimo.in.
  7. Mark key events: generate_lead, begin_checkout (Admin → Events).
  8. Register custom definitions (dimensions): web_vitals_metric, web_vitals_rating, lead_type, lead_topic, lead_budget, search_term (dimension), result_count, link_domain, video_title.
  9. Admin → Product links → Search Console → link the existing property (site verification meta is already in __root.tsx).

2.2 Shopify → GA4 (this is what makes purchases visible)

  1. Shopify Admin → Settings → Apps → Google & YouTube channel → install.
  2. Connect the same Google account and select the GA4 property from 2.1.
  3. Shopify then injects the Google tag on shop.mozimo.in (storefront + checkout) and reports purchase/begin_checkout/add_to_cart into the property. The cross-domain linker on both sides stitches sessions — verify a _gl= parameter appears when clicking Order this on a product page.
  4. Place one real (then refunded) test order and confirm purchase in GA4 Realtime/DebugView.

2.3 Sentry

  1. sentry.io → create project mozimo-web (platform: TanStack Start / JavaScript).
  2. Copy the DSN into your local .env (VITE_SENTRY_DSN) and into ansible/files/.env (SENTRY_DSN) — client needs it at build, server at runtime.
  3. Optional sourcemap upload (better stack traces): put SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT in the build machine env. Builds without them skip Sentry's vite plugin entirely.
  4. Verify: visit any page with ?sentry-test=1… simplest check is a thrown error in devtools; a visible page_view + the event landing in Sentry is enough for sign-off.

2.4 Vince (first-party layer)

  1. ./deploy.sh once — the playbook creates the container (command: serve) with VINCE_ADMIN_NAME / VINCE_ADMIN_PASSWORD from ansible/vars/default.yml (change the password there before deploying) and auto-creates the mozimo.in site via VINCE_DOMAINS.
  2. Add a DNS record for stats.mozimo.in (same server IP) — Caddy publishes the dashboard there; log in at https://stats.mozimo.in/login with the admin name/password from the ansible vars.
  3. Set VITE_PLAUSIBLE_DOMAIN=mozimo.in in your local .env and redeploy — the script tag (with data-api="/stats/api/event") is injected only when this is set.
  4. Check https://<www_host>/stats/js/script.js returns the script (200) and that browsing the site populates stats.mozimo.in/<domain> within seconds.
  5. With uBlock Origin enabled: visits still appear in Vince but not GA4 — expected and exactly why this layer exists.

3. Verifying GA4 events (DebugView)

Append ?debug_mode=1… simpler: build with VITE_GA4_DEBUG=1 in .env temporarily — every event then carries debug_mode: true and appears in GA4 Admin → DebugView (with the Tag Assistant Companion extension).

Walk-through: home (page_view, view_item_list The Mozimo Edit) → /chocolate → /collections/bars (view_item_list) → a product (view_item) → Order this (begin_checkout + outbound click with _gl) → /contact submit (generate_lead) → search overlay (search).

4. Operational notes

  • Dev is always excluded — analytics scripts only inject in production builds.
  • Disabling a tool = leaving its env var empty. Nothing breaks.
  • Changing the GA4 property = change the env var and redeploy.
  • Sitemap (dist/client/sitemap.xml from scripts/generate-sitemap.mjs) and robots.txt are live for Search Console; submit the sitemap once in Search Console → Sitemaps.
  • Phase 2 (in-container cart) should add add_to_cart, view_cart, remove_from_cart via the same helpers in src/lib/analytics.ts.