EasyStarter logoEasyStarter

Analytics

Configure Google Analytics 4 and OpenPanel, then track only key funnel events

Analytics

EasyStarter Web ships with two optional analytics providers. Both are skipped automatically when their environment variables are empty:

ProviderPurpose
Google Analytics 4Traffic, conversion funnels, audience reports
OpenPanelOpen-source, privacy-friendly product analytics (events, retention, funnels)

You can enable either, both, or neither — leave the variable blank to disable.

Track only the key funnel events by default: signup completed, login succeeded, subscription started, core generation finished, submission created, and similar conversion points. The template keeps GA4 page views enabled, but OpenPanel does not automatically track every route change so free-tier usage is not spent on low-signal navigation events.

Google Analytics 4

Create a GA4 property and grab the Measurement ID

Official docs: Find your Google tag / Measurement ID

  1. Visit analytics.google.com and sign in
  2. Open Admin → Create → Property, fill in product name, time zone, currency
  3. Inside the new property, pick Data Streams → Add stream → Web
  4. Enter the site URL (e.g. https://yourdomain.com) and create the stream
  5. Copy the Measurement ID shown on the stream detail page — format G-XXXXXXXXXX

Set environment variables

Local development (apps/web/.env.development):

apps/web/.env.development
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX

Local production deploy (vars block of apps/web/wrangler.jsonc, plain text — not a Secret):

apps/web/wrangler.jsonc
{
  "vars": {
    "VITE_GA_MEASUREMENT_ID": "G-XXXXXXXXXX",
    // ...
  }
}

CI / remote-deploy variable list (apps/web/.env.production):

Used by local production builds (pnpm build:web:production) and as the canonical list of variables to mirror into Cloudflare's build environment when deploying from GitHub:

apps/web/.env.production
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX

VITE_-prefixed values end up in the client bundle and aren't sensitive — keep them in wrangler.jsonc / CI build variables, no pnpm run secrets:bulk:production needed. .env.production is gitignored and stays local.

Track key events explicitly

The Web app exposes small tracking helpers. Call them only from conversion points that matter to the product:

import { trackGoogleEvent } from "@/lib/analytics/google-analytics";
import { trackOpenPanelEvent } from "@/lib/analytics/openpanel";

trackGoogleEvent("sign_up", {
  method: "google",
});

trackOpenPanelEvent("subscription_started", {
  plan: "pro",
});

If a route is truly part of the product funnel, record an OpenPanel screen view manually:

import { trackOpenPanelScreenView } from "@/lib/analytics/openpanel";

trackOpenPanelScreenView("/pricing");

Do not treat every route transition as a product event. Start with 3-5 key funnel steps, then add more events when the data answers a real product question.

OpenPanel

OpenPanel is an open-source product analytics platform. You can self-host it or use the Cloud version — the free tier is plenty for an indie project. EasyStarter targets the Cloud version by default.

Create an OpenPanel project

Official docs: Web SDK

  1. Sign up at openpanel.dev
  2. In the dashboard click Create Project
  3. Fill in Project name
  4. Keep Website enabled, and turn off App and Backend / API unless you need them now
  5. Enter the production site URL in Domain, e.g. https://yourdomain.com
  6. Add event-ingestion origins under Allowed domains, e.g. https://yourdomain.com
  7. Click Create project
  8. After creation, copy the Website Client ID from the project's client details (UUID)

Set environment variables

Local development (apps/web/.env.development):

apps/web/.env.development
VITE_OPENPANEL_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Local production deploy (apps/web/wrangler.jsonc):

apps/web/wrangler.jsonc
{
  "vars": {
    "VITE_OPENPANEL_CLIENT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    // ...
  }
}
apps/web/.env.production
VITE_OPENPANEL_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Also a public value. For CI deploys, add it to the platform's build variables, not the secrets section.