The fastest way to build apps with Next.js, Supabase, and privacy-friendly analytics
Features · Demo · Deploy to Vercel · Clone and Run Locally · Project Structure
This template extends the official Next.js Supabase Starter with PulseKit — a lightweight, privacy-friendly analytics toolkit that stores all data in your own Supabase database.
- Next.js App Router — works across Server Components, Client Components, Route Handlers, Server Actions, and Middleware
- Supabase Auth — cookie-based authentication via
@supabase/ssr, with password-based auth from the Supabase UI Library - PulseKit Analytics — automatic page view tracking, Web Vitals (LCP, INP, CLS, FCP, TTFB), error reporting, and geo-location stats
- Analytics Dashboard — built-in dashboard at
/admin/analyticswith password-protected access - Data Lifecycle — automatic aggregation and cleanup of old raw events to keep your database lean
- Security Hardened — RLS policies with minimum-privilege grants per role, validated event types on insert
- Tailwind CSS + shadcn/ui — styled with Tailwind CSS and shadcn/ui components
You can view a fully working demo at https://with-supabase-pulsekit-template.vercel.app/.
Vercel deployment will guide you through creating a Supabase account and project. After installation of the Supabase integration, all relevant environment variables will be assigned to the project so the deployment is fully functioning.
After deploying, you will still need to:
- Set the
PULSE_SECRETenvironment variable in Vercel (a 16+ character password for your analytics dashboard) - Set the
SUPABASE_SERVICE_ROLE_KEYenvironment variable in Vercel - Run the database migrations (see below)
Create a new project via the Supabase dashboard.
git clone https://github.com/benoiteom/with-supabase-pulsekit.git
cd with-supabase-pulsekit
npm installRename .env.example to .env.local and fill in the values:
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-publishable-or-anon-key
PULSE_SECRET=your-analytics-dashboard-password
SUPABASE_SERVICE_ROLE_KEY=your-service-role-keyNote
NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY can be found in your Supabase project's API settings. SUPABASE_SERVICE_ROLE_KEY is in the same place under "Service Role". PULSE_SECRET is a password you create (16+ characters) to protect your analytics dashboard.
Link your Supabase project and push the PulseKit schema:
npx supabase link
npx supabase db pushThis creates the analytics schema with tables for events and aggregates, plus RPC functions for querying stats.
npm run devThe app should now be running on localhost:3000.
├── app/
│ ├── admin/analytics/ # PulseKit analytics dashboard (password-protected)
│ ├── api/pulse/ # Analytics API routes (ingestion, auth, aggregation, cleanup)
│ ├── auth/ # Supabase auth pages (login, sign-up, callback, etc.)
│ └── protected/ # Example protected page
├── components/
│ ├── pulse-tracker-wrapper.tsx # PulseKit tracker (auto page views, vitals, errors)
│ └── tutorial/ # Setup guide shown on the home page
├── instrumentation.ts # Server-side error reporting via PulseKit
├── lib/supabase/ # Supabase client helpers and middleware proxy
└── supabase/migrations/ # SQL migrations for the analytics schema
- Tracking —
PulseTrackerWrapperin the root layout automatically captures page views, Web Vitals, and client-side errors. No manual instrumentation needed. - Server Errors —
instrumentation.tsusescreatePulseErrorReporterto capture server-side errors via Next.js'sonRequestErrorhook. - Ingestion — Events are sent to
/api/pulsewhich writes them to theanalytics.pulse_eventstable in Supabase. - Dashboard —
/admin/analyticsrenders thePulseDashboardcomponent, protected byPulseAuthGate(usesPULSE_SECRET). - Data Lifecycle —
/api/pulse/consolidaterolls old raw events into daily aggregates and cleans up, keeping your database lean.
- PulseKit: github.com/benoiteom/pulsekit/issues
- Supabase: github.com/supabase/supabase/issues
