Basis

Privacy

Last updated 29 June 2026

What we collect from Spotify

When you sign in with Spotify, Basis requests these OAuth scopes: user-top-read (your top artists and tracks), user-read-email, user-read-private, and user-read-recently-played (currently requested but not yet stored — we kept the scope for a future feature). We use these to fetch your display name, profile picture, and your top artists/tracks.

Genres are derivedfrom the artists' MusicBrainz metadata — we don't request them from Spotify. We do not request your playlists, your followers, or your full listening history.

What we store

Your Spotify data is stored in a Postgres database (hosted on Supabase, EU region) alongside the public profile fields you provided (display name, bio, country). Cached data (MusicBrainz artist metadata, album art URLs) is fetched from the public MusicBrainz API and stored alongside your Spotify rows. Access and refresh tokens are stored in the users.providers jsonb column — see "Security" below. We do not store your raw Spotify audio.

What we do with it

  • Display your top artists, tracks, and genres on your profile
  • Show your reviews to your followers
  • Compute a taste profile used for friend recommendations
  • Generate shareable OG images for your profile

Nothing else. We do not analyse your listening for advertising or benchmarking. We do not export your data to any other service. We do not train machine learning models on Spotify data.

Disconnect & delete your data

You can disconnect your Spotify account at any time from /settings. The Disconnect button is shown only to the signed-in account owner. Clicking it shows a confirmation; on confirm, Basis:

  1. Deletes your top artists, top tracks, top genres, reviews, badges, follows, and comparisons
  2. Deletes the resolver scratch rows (unresolved artist/track lookups)
  3. Deletes your user row (cascade handles anything missed)
  4. Calls Spotify's token-revoke endpoint to invalidate the refresh token
  5. Clears your session cookie and redirects to /welcome

After disconnect, every /u/<your-username> page is a 404. The data is unrecoverable.

Cookies & sessions

We use a single signed session cookie (HttpOnly, Secure, SameSite=Lax) to keep you signed in, plus an HttpOnly double-submit CSRF cookie for mutating requests. We do not use third-party tracking cookies or analytics scripts.

Security

Access and refresh tokens are stored in the database as plain JSON in the users.providers column (the tokens are short-lived and the column is only readable by the application role, not exposed to the public schema). The session cookie is signed with an HMAC of AUTH_SECRET. OAuth state is a one-time HMAC-signed nonce bound to the callback URL. Mutating endpoints (logout, disconnect, OAuth callback) are protected by a Redis-backed rate limiter (10 requests per IP per minute on auth routes).

The following security headers are set on every response: Strict-Transport-Security (HSTS, 2 years), X-Content-Type-Options (nosniff), Referrer-Policy (strict-origin-when-cross-origin), X-Frame-Options via Content-Security-Policy frame-ancestors 'none', and a Content-Security-Policy that restricts scripts/styles/images/connects to known-good sources.

Contact

Questions or data requests: privacy@basis.fm. We respond within 30 days.