Analytics
Three analytics systems in one — built-in, GA, PostHog.
DirectoryKit records usage in up to three places at once. Turn on whichever you need.
| System | Data home | What it's best for |
|---|---|---|
| Built-in enhanced analytics | Your Supabase DB | Fast admin charts, no cookies |
| Google Analytics 4 | SEO reports, acquisition | |
| PostHog | PostHog cloud | Funnels, session replay, feature flags |
Setup for GA and PostHog is in Analytics Config.
Built-in analytics
Requires the analytics feature flag (on by default).
What gets tracked
| Event | Where |
|---|---|
| Page views | Every page |
| Project views | /project/[slug] |
| Category views | /categories/[slug] |
| Submission funnel steps | /submit |
| Click-outs (visits to project URLs) | Project cards |
| Device, browser, OS | All of the above |
| Country (from IP) | All of the above |
Events are written to the analytics table via lib/analytics.ts. No personally identifying data — no IPs stored, no emails, no names.
Admin dashboard

Charts come from Recharts. Filters: date range, event type, project (drill-down).
Use it in your code
import { trackEvent } from '@/lib/analytics';
await trackEvent('project_clicked', {
project_id: app.id,
source: 'homepage',
});Google Analytics 4
Set NEXT_PUBLIC_GA_MEASUREMENT_ID in .env.local. The tag auto-injects into <head>. See Analytics Config for step-by-step.
Events sent to GA:
- Page views (auto)
project_viewed,project_clicked,submission_started,submission_completed
PostHog
Set NEXT_PUBLIC_POSTHOG_KEY and NEXT_PUBLIC_POSTHOG_HOST. The SDK initializes on page load.
Good for:
- Funnel:
/submitstep drop-off - Session replay on premium submits
- A/B tests via feature flags
- Per-user cohorts
Turning it all off
Disable GA / PostHog by removing their env vars. Disable the built-in tracker with analytics: false in features.config.ts.
Privacy note
The built-in tracker stores no PII by default. If you want to comply with GDPR-style consent:
- Use a cookie banner component
- Check consent before calling
trackEvent() - Flip the
SiteTrackerprovider to respect the consent cookie
The code is intentionally simple — you own the data, you decide the policy.