SaaS companies copy the same tag plan: Google Analytics 4 on the marketing site, then the same property (or a second web stream) inside the authenticated app, because “we already have GA4”. Six months later the signup funnel is an Exploration nobody trusts, SPA pageviews double-count, and the growth lead is reconciling GA4 users against the users table. That is not a configuration error. It is the wrong instrument.
SiteLine is also the wrong instrument inside the product, and we will say so before the comparison table. It is a cookieless marketing-site analytics tool with Search Console in the same account. Custom events exist. They are not Mixpanel. If you need identity across days, feature-flag experiments, or a warehouse of product events, keep PostHog / Mixpanel / Amplitude / your own pipeline. Use SiteLine where Google-shaped analytics actually hurts: the public site, organic acquisition, and a funnel you can explain to a founder.
The SPA tax
GA4’s recommended SPA pattern is a history-change event or a tag that fires on route change. Miss one router, and /app is a single pageview. Double-fire, and every client navigation is two. Next.js App Router has edge cases that bypass pushState patching. This is not unique to Google; SiteLine’s script has the same class of problem and documents it: it listens for popstate and lightly patches pushState / replaceState. When a framework still skips those, call trackPageview() from @siteline.tools/react.
The difference is operational. A cookieless marketing site with a dozen routes is a solvable install. An authenticated app with nested routers, feature drawers, and billing webviews is a product-analytics project. Do not drag a privacy-first page counter into it and then complain it lacks user-id.
Event cardinality vs ten properties
GA4 will let you send a lot of parameters until you hit cardinality limits and the reports fill with “(other)”. Product teams then invent event taxonomies, naming committees, and a tracking plan in Notion that is six months stale.
SiteLine caps custom events at 10 properties, key length 64, value 256, types string / number / boolean. Extra keys drop; long values truncate. Ingest enforces the same limits as the client. Outbound-link and file-download tracking are opt-in and are billable custom events — leave them off unless you need them. Goals match exact path, path contains, or event name; funnels are ordered lists of those matches. Defining a goal does not emit an extra event. See /docs/events and /docs/goals.
That cap is the point. signup_completed with {plan: "growth"} belongs here. client_workspace_id plus twenty feature flags does not.
What a SaaS funnel should be on the public site
| Step | Sensible instrumentation | Not this |
|---|---|---|
| Blog / docs | Pageviews, referrer, UTMs | User-id, replay |
| Pricing | Pageview + optional plan_viewed |
Full product schema |
| Trial start | signup_clicked or /register pageview |
Cross-day “users who saw pricing in Q2” |
| Activated in-app | Your product analytics / database | SiteLine visitor hash |
| Organic demand | Search Console queries, pages, position | GA4 “organic search” channel |
SiteLine unique visitors are a daily SHA-256 of truncated IP (/24, /48) + user agent + rotating salt, reset UTC midnight, no analytics cookie, credentials: 'omit'. Conversion rate is unique visitors who hit the goal in range. You can answer “what share of today’s pricing visitors reached /register”. You cannot answer “what share of April visitors retained to June”. Stop asking the marketing tracker that question.
Search Console answers a different SaaS question: which queries actually produce impressions and clicks for /pricing and /docs/.... SiteLine backfills 16 months read-only (webmasters.readonly), 25k rows/day/report, reimport every 4 hours of the last 7 days, including fresh data before Google finalizes it, CTR computed. Unlimited sites. That history is usually more important to a B2B SaaS than another GA4 audience.
Pricing without a surprise invoice from “events”
SaaS marketers hear “event” and think Mixpanel monthly events. SiteLine billable events are pageviews plus custom events, shared across unlimited analytics domains. Starter $4.99 / 1M, Growth $19.99 / 10M, Scale $99.99 then $2.99 per extra 1M. 7-day trial, card required, ~50k visibility so trials are not a free CDN for events. Starter/Growth soft-cap hides post-cap data; Scale meters. 30-day analytics grace after access ends. MCP for Claude, ChatGPT and Cursor is included — useful when a founder asks “what did we rank for last month?” in the same tool that has the thank-you page goal.
A first-party proxy is worth it on a SaaS marketing site if docs traffic is technical and full of blockers. You configure the reverse proxy; SiteLine does not manage CNAMEs in v1.
Do not use SiteLine for Ads attribution. Keep GA4 or the Ads tag if paid is real. The split is the mature setup: product analytics in the app, cookieless + GSC on the site. Broader map: GA4 alternatives. Why people actually leave: why teams leave GA4. Direct grid: SiteLine vs Google Analytics.
FAQ
Can we put SiteLine on the logged-in app?
You can install the script anywhere the hostname is allowlisted. You should not treat it as product analytics. There is no user-level identity across days, no session replay, and a 10-property event cap. Instrument the app with a tool built for that, and keep SiteLine on the public origin.
How do we track trial starts without a user id?
Send a named event (signup_completed) or land on a stable thank-you path and attach a goal in the UI. Both count unique visitors for the day they fired, not a person over a month. Match that to your database for the real trial count.
Does MCP replace a tracking plan?
No. MCP lets an authorised agent query Search Console and analytics that already exist. It will not design your event names. Keep names lowercase and stable; the agent can then ask for signup_completed without inventing a schema.