Hosted App Analytics

Privacy-friendly traffic analytics for Gencow-hosted frontend apps, including automatic script injection, Dashboard metrics, country attribution, and query scrubbing

Gencow-hosted apps get privacy-friendly web analytics without adding a third-party tracker. When you deploy frontend HTML through Gencow, the platform injects a same-origin analytics script, records scrubbed pageview events, and shows traffic inside the app's Dashboard Analytics tab.

The analytics path is owned by Gencow:

Browser on your hosted app
  -> /_gencow/analytics.js
  -> POST /_gencow/analytics/event
  -> Gencow Analytics collector
  -> Dashboard Analytics tab

Your app does not need to know the analytics database, table names, rollup strategy, or storage backend. The public contract is the same-origin script and collector route.

When It Runs

Analytics runs for frontend pages served by Gencow static/fullstack hosting:

bun run build
gencow deploy --static dist/

The platform injects a deferred script into HTML responses:

<script defer src="/_gencow/analytics.js" data-deploy="<deployId>"></script>

You usually do not add this tag yourself. Gencow injects it when the deployed asset is HTML and analytics is enabled for the app/site.

Deployment shape Behavior
Gencow-hosted HTML Script is injected automatically
Gencow-hosted SPA route Route changes are tracked through History API hooks
Gencow-hosted asset-only deploy No HTML means no script injection
Externally hosted frontend Automatic injection is not available

The analytics endpoints are reserved platform paths. Do not create app routes under /_gencow/analytics.js or /_gencow/analytics/event.

What Gets Tracked

The default event is pageview. The script records the first pageview and SPA route changes. It sends a bounded payload with safe browser metadata:

Field Meaning
eventName pageview by default, or a custom event name
url / path Current page URL after query scrubbing
referrer Referrer after same-origin and query scrubbing rules
utm_* Standard UTM fields when present
screen Screen width/height bucket, not a high-precision fingerprint
language Browser language
timestamp Client timestamp; server receive time remains authoritative
deployId Current deploy id when available

You can record a simple custom event from browser code:

window.gencow?.analytics?.track?.("signup_completed");

Keep event names short and non-sensitive. Do not include user ids, emails, tokens, prompt text, storage grant URLs, or form values in event names.

Privacy And Security

Gencow analytics is designed for aggregate product traffic, not user tracking.

  • raw IP is not stored
  • email, name, user id, cookies, localStorage, sessionStorage, request bodies, form values, prompts, and file contents are not collected
  • the collector uses request-scope IP only to derive a visitor/session key and a country code
  • country attribution stores country only; region and city are not collected
  • DNT/GPC is respected by the browser script
  • known crawler, smoke-test, oversized, and rate-spike traffic can be dropped
  • if analytics storage is unavailable, the collector fails open so page loads are not blocked

The query scrubber keeps ordinary attribution data and removes secret-like parameters before storage. UTM fields such as utm_source, utm_medium, utm_campaign, utm_term, and utm_content are allowed. Parameters such as token, code, secret, key, password, session, and grant are removed even if they appear beside UTM fields.

Example:

https://example.com/pricing?utm_source=newsletter&token=abc&code=oauth

Stored page dimension:

/pricing?utm_source=newsletter

Dashboard Metrics

Open Dashboard -> App -> Analytics to inspect traffic.

Metric Meaning
Visitors Distinct privacy-preserving visitor keys for the selected period
Visits Session count for the selected period
Pageviews Count of pageview events
Views per visit Pageviews divided by visits
Bounce rate Share of visits with a single pageview when the backend can compute it
Visit duration Aggregate visit duration when enough session data is available
Current visitors Recent active visitor estimate

Reports group the same traffic by source, page, country, device, browser, OS, and goals/events. Row clicks add filters to the current Dashboard view so you can answer questions such as:

Question Dashboard path
Which pages attracted traffic this week? Select 7d -> Pages
Did a campaign send useful visitors? Select date range -> Sources -> filter by UTM source
Which countries are visiting after launch? Countries report
Are mobile users bouncing more? Devices report -> compare bounce rate

Country Attribution

Country is derived at collection time. Gencow first uses trusted country headers from the edge/proxy when available. If no country header is present, the platform can use a local country GeoIP database to derive a country code from the request-scope client IP. Only the country dimension is stored.

If the country database is unavailable, analytics remains available and country falls back to Unknown. Your app still loads normally.

Custom Domains

Analytics follows the active Gencow site mapping. Official subdomains and active custom domains both use the same same-origin script path:

https://my-app.gencow.app/_gencow/analytics.js
https://www.example.com/_gencow/analytics.js

The collector resolves the app/site from the request host and platform domain mapping. It does not trust client-sent app ids or site ids for ownership.

Troubleshooting

Symptom Check
No pageviews after deploy Confirm the deployed HTML is served by Gencow and includes /_gencow/analytics.js
SPA navigation not counted Confirm the app uses normal History API navigation; hard reloads and route changes should both send pageviews
Country shows Unknown Edge country headers or the platform country database may be unavailable
Local browser not counted DNT/GPC may be enabled, or browser extensions may block analytics requests
Custom domain traffic missing Confirm the domain is active and serving the Gencow-hosted app

Analytics should never require provider API keys, database credentials, or application secrets in frontend code.