Analytics
gitfor can send product analytics to PostHog: web analytics (pageviews), autocapture, heatmaps, session replay, feature flags and a few server-side events. Like billing, it's optional. With no POSTHOG_KEY, nothing loads: posthog-js isn't downloaded, no server events are sent, and the settings opt-out panel is hidden.
Configuration
| Variable | Purpose |
|---|---|
POSTHOG_KEY |
Project token (phc_...). Enables analytics. VITE_POSTHOG_PROJECT_TOKEN is accepted as an alias. |
POSTHOG_HOST |
Ingestion host, https://us.i.posthog.com by default (https://eu.i.posthog.com for EU). VITE_POSTHOG_HOST alias. |
POSTHOG_PERSON_EMAIL |
true attaches the signed-in user's email to their PostHog person. Off by default. |
These are read at runtime, so self-hosters don't need to rebuild to turn analytics on or off. The page CSP currently restricts only img-src. The PostHog host is added there only when it is configured, and must also be added to any script-src or connect-src directives introduced later.
Privacy
- Consent signals. Do Not Track and Global Privacy Control turn analytics off. Each browser can also opt out under Settings -> Account -> Product analytics.
- Origins. It runs only on the forge's own origin (
PUBLIC_URL), never on the editor, user-content, sites or pages origins. - No PII by default. People are identified by their opaque account id. Emails are attached only with
POSTHOG_PERSON_EMAIL=true. gitfor.dev turns this on. Once on, the email is also added to people who were identified earlier, on their next page load. The project also has IP anonymization on. - URLs.
- Query strings and fragments are always dropped.
- Repository paths are reduced to
/[private]/[private]/<section>unless the page has confirmed the repository is public, so private repository names and file paths never leave the browser. - Links to other sites keep only their origin.
- Autocapture records no element text or attributes.
- Session replay.
- All inputs are masked, and all text is masked except on public repository pages (dashboards, profiles, search and notifications list private repository names).
data-ph-maskmasks an element even there. - Replay pauses before navigating to a repository not known to be public, and to settings, admin and sign-in pages.
- Console logs and network bodies and headers are not captured.
- All inputs are masked, and all text is masked except on public repository pages (dashboards, profiles, search and notifications list private repository names).
- Server events carry only enums and counts, never names, emails, subjects or private repository names.
Events
Browser: $pageview, $pageleave, autocapture, heatmaps, web vitals and replay.
Server (src/server/analytics.ts, sent via waitUntil with a 3 second timeout; failures are swallowed so they can never block or fail a request):
| Event | Properties |
|---|---|
user_signed_up |
method (password or github) |
user_signed_in |
|
org_created |
org_id |
repo_created |
visibility, owner_kind, init_readme |
email_sent |
outcome (sent, disabled, dev_sink), thread_reply; no person |
subscription_changed |
status, plan |
credit_purchased |
pool, quantity, pack, amount_cents |
mergefix_started |
trigger, mode, private_repo |
pull_description_suggested |
byok |
Feature flags
useFeatureFlag("flag-key", fallback) (src/hooks/use-feature-flag.ts) returns the PostHog flag, or fallback while flags load and on instances without analytics. Code must always work with the fallback.
Project settings
The hosted project allows https://gitfor.dev for the toolbar and replay, and has these settings:
- On: session replay, autocapture, heatmaps, web vitals, performance capture and IP anonymization.
- Off: console log capture, exception autocapture, and network headers and bodies in replays.
Self-hosters should set their own domain in PostHog's project settings.