one initAnalytics() in main.tsx · SPA routes autocaptured · open source (MIT)

Add analytics to React.
One init in your entry file.

A tiny initAnalytics() in main.tsx injects the SDK once and calls smolanalytics.init. SPA route changes autocapture, and track() / identify() mark the moments that matter. Framework-agnostic: Vite, CRA, any React app.

main.tsx · the whole install
// inject /sdk.js once, then init. SPA routes autocapture.
function initAnalytics() {
  const s = document.createElement("script");
  s.src = "https://your-instance/sdk.js";
  s.onload = () => window.smolanalytics.init({ site: "prj_live" });
  document.head.appendChild(s);
}
initAnalytics();

// mark key moments from any component
window.smolanalytics.identify(user.id);
window.smolanalytics.track("trial_started");

// or a one-line hook on a button
const track = useTrack();
<button onClick={() => track("upgrade_clicked")}>Upgrade</button>

how do I add analytics to a React app?

To add analytics to a React app, put a tiny initAnalytics() in your entry file (main.tsx or index.tsx) that injects the smolanalytics (smolanalytics.com) SDK script once then calls smolanalytics.init with your site id. That single call gives you pageviews across your single-page app, because the SDK autocaptures client-side route changes, so soft navigations count as real pageviews, plus visitors, referrers, funnels, retention, and paths. For key moments you call window.smolanalytics.track("signup_clicked") and window.smolanalytics.identify(userId) from anywhere in your component tree, and a tiny useTrack hook wraps that so a button's onClick is one line. Because identify keys off a stable distinct_id, a user's first pageview, their signup, and the server events you POST to /v1/events (payments, provisioning, webhooks) fuse into one funnel. It works the same in Vite, Create React App, or any React SPA, because the install is one script tag plus one init, framework-agnostic. It is an open-source single Go binary you self-host free forever, or a hosted instance from $9/month, and instead of building dashboards you ask it "where do users drop off?" in plain English and the answer is computed from your events, never guessed.

one script tag and one init, not a framework plugin

One initAnalytics() in your entry file
In main.tsx or index.tsx, a small initAnalytics() injects /sdk.js once, then calls smolanalytics.init(siteId). That is the whole client install. It works the same in Vite, Create React App, or any React setup, because it is one script tag and one call, not a framework plugin.
SPA route changes autocaptured
The SDK hooks client-side navigation, so a soft route change in React Router (or wherever) counts as a real pageview, not a single load at boot. You get pageviews, visitors, referrers, and paths across your whole single-page app from that one init, no per-route wiring.
track() and identify() for key moments
Call window.smolanalytics.track("trial_started") or window.smolanalytics.identify(userId) from any component, and a tiny useTrack hook makes a button one line: const track = useTrack(); onClick={() => track("upgrade_clicked")}. Mark exactly the moments that matter to your funnel.
Client and server, one funnel
The browser never sees a Stripe webhook or a cron run. POST those to /v1/events from your server with the same distinct_id you set via identify(), and a user's pageview, signup, and payment join into one person's timeline. Then ask "where do users drop off?" from the dashboard or your own Cursor / Claude over MCP.

Honest pricing: 14-day full trial, no credit card. Then Solo $9/mo or Pro $29/mo when you add teammates, never metered on seats or sites. Overage is $5/million with an emailed receipt, the dashboard never locks, and self-hosting the single Go binary is free forever (MIT).

Paste initAnalytics() tonight.

One init in your entry file, SPA routes autocaptured, track() and identify() for the moments that matter. Tomorrow morning the verdict tells you which part of the funnel to fix.

questions

How do I add analytics to a React app?
Put a tiny initAnalytics() in your entry file (main.tsx or index.tsx). It injects the SDK script once (const s = document.createElement("script"); s.src = "https://YOUR_INSTANCE/sdk.js"; s.onload = () => smolanalytics.init({ site: "YOUR_SITE_ID" }); document.head.appendChild(s);), then you are done. That gives you pageviews (including SPA route changes), visitors, referrers, funnels, retention, and paths from one call. Mark key moments with window.smolanalytics.track() and window.smolanalytics.identify().
Does it track single-page route changes?
Yes. The SDK hooks client-side navigation, so soft route changes in React Router (or any router) are counted as pageviews, not just the one hard load when the app boots. You do not wire anything per route: init once in your entry file and every navigation in the single-page app becomes a pageview automatically.
How do I track a button click or a signup?
Call window.smolanalytics.track("signup_clicked") from the handler, and window.smolanalytics.identify(userId) once you know who the user is. A tiny useTrack hook wraps track() so a component is one line: const track = useTrack(); return <button onClick={() => track("upgrade_clicked")}>Upgrade</button>. Those events flow straight into your funnels and paths.
How do client-side and server-side events end up as one user?
The same distinct_id. Call smolanalytics.identify(userId) in the browser and send that same value as distinct_id when you POST /v1/events from your server, and a user's React-side activity and their server events (payments, provisioning) join into one person's timeline and one funnel. Pick a stable id, your own user id works.
Do I need a cookie banner?
Not in cookieless mode. smolanalytics can run without cookies, so there is no consent banner to bolt onto your React app. You still get visitors, referrers, funnels, retention, and paths, and AI-assistant referrals (chatgpt.com, claude.ai, perplexity.ai) show up as their own channel.
Is it enough for a real React product, or just page counts?
It does funnels, retention, paths, cohorts, channel-and-revenue attribution, and a daily verdict on what to fix, across client and server events. It deliberately does not do session replay, feature flags, heatmaps, or experiments, if you need those keep a tool like PostHog for them. It is for teams who want a straight answer on what to fix, that they own, cheap.

keep reading