Security
The default schema is optimized for self-hosted demos and quick setup. Before exposing a public instance, review these risks and mitigations.
Supabase anon key in the browser
The standard embed snippet includes the site project's anon key. Anyone can read it from your page source. With default RLS, that key can:
- Insert events for valid
site_keyvalues - Read all events (dashboard policy allows
selectfor anon)
Mitigations:
- Use
data-endpointand a server route that validates payloads instead of exposing the publishable key in HTML. - Tighten RLS: remove broad
selectfor anon; authenticate dashboard users and use user-scoped policies. - Restrict inserts by IP or rate limit at the edge.
App vs analytics projects
The app Supabase project (`.env`) should only hold accounts and site bookmarks. Your analytics Supabase project holds events — tighten anon policies there before high traffic.
Bot traffic
The tracker skips common bots via User-Agent regex. This does not stop:
- Bots that mimic a normal browser
- Direct API inserts into
events - Historical bot data already stored
Server-side filtering would require storing user_agent or an is_bot flag and excluding those rows in aggregations.
Privacy
- Visitor identification uses a fingerprint +
localStorage— disclose this in your privacy policy where required (e.g. GDPR). - Optional
data-do-not-track="true"respects browser DNT when enabled. identify()can attach a logged-in user id; treatdistinct_idas personal data if it maps to accounts.- Geo uses approximate location from IP via your geo endpoint — document retention.
Production checklist
- Replace open RLS with auth-backed policies.
- Keep app and analytics Supabase keys scoped; rotate if leaked.
- Set
NEXT_PUBLIC_APP_URLto HTTPS production origin. - Enable Supabase rate limiting / WAF as needed.
- Rotate anon/service keys if leaked.
- Back up per-site Supabase projects regularly.