Analytics

Track storefront activity through Umami, Google Analytics, or both — without leaking personal information.

Configuration

Each tenant can connect a Umami website ID and/or a Google Analytics 4 measurement ID. Set these on the tenant record (Platform Admin → Tenants → edit). Scripts only load in production when the corresponding ID is present.

What gets tracked

Beyond automatic page views, the platform fires a typed set of business events from the customer-facing site, the admin app, and the instructor app:

  • Conversionsbooking_completed, checkout_completed, signup_completed, login_completed
  • Funnelcourse_view, schedule_view, product_view, cart_add, checkout_started, booking_started, waitlist_join
  • Engagementsearch, filter_applied, discount_applied, discount_code_failed, contact_submit
  • Frictionpayment_failed, booking_blocked_prereq, out_of_stock
  • Lifecycleenrollment_cancelled (with actor set to customer or admin)
  • Admin / instructoradmin:course_created, admin:invoice_sent, admin:order_refunded, instructor:session_marked_complete

Filtering staff activity

Events fired inside the admin or instructor surfaces — or with an admin: / instructor: namespace — are tagged with is_internal: true. Funnel dashboards should filter on this tag so staff dogfooding doesn't pollute customer conversion data.

Server-side delivery

Conversion events that don't have a reliable client (webhooks, redirect-driven OAuth flows, background jobs) are emitted from the server via Umami's send API and the Google Analytics 4 Measurement Protocol. The Square payment.completed webhook, for example, re-asserts checkout_completed so checkouts aren't lost when the customer tab is closed or ad-block strips the client beacon. Each event is delivered by exactly one side to avoid double counting. Configure with the UMAMI_HOST and GA_API_SECRET environment variables.

User identification

When a user is signed in, their internal user ID is passed to both backends as a stable identifier for cross-device attribution and conversion reporting. No emails, names, or other personal details are sent. The identifier is cleared on logout.

Privacy

Event payloads contain only non-identifying details — internal resource IDs, amounts, currency, item counts, route group, and locale. We never send emails or IP-derived data. Search queries are lowercased, trimmed, and limited to 100 characters.

Google Analytics 4 mapping

Conversion events map to GA4's recommended event names so Google's built-in Monetization, Acquisition, and Conversions reports populate automatically: checkout_completed and booking_completed become purchase; signup_completed becomes sign_up; search stays as search with search_term. Other events fire under their original snake-cased names.