privacy + DSAR.
we hold three classes of data: your account data, your audience’s data, and analytics events. each one’s handled differently. all of it is exportable; most of it is erasable.
your account data.
- email + password (hashed via supabase auth, bcrypt-style).
- workspace memberships, roles, audit log entries.
- api keys (we store SHA-256 hashes only; never plaintext).
- stripe customer id (no card data ever touches our servers).
you can delete your account from settings. that erases the owned workspaces (links + destinations + redirects) and removes you from any workspace where you’re a member.
your audience’s data.
when people interact with your links (pre-save, email capture), we hold:
- their email and/or phone + (sometimes) first name. a phone is only kept for SMS / WhatsApp they explicitly opted into (“ok to text or WhatsApp me”), and they can reply STOP anytime.
- a coarse country (country only, derived from the edge; never region or city) + how they opted in (form / pre-save), so you can segment your own list.
- if your workspace belongs to a label (an org with more than one artist), the label can send a person a genre-matched note about another artist on the same roster. every such email says why they’re getting it and carries a one-tap “stop hearing from other label artists” link that suppresses cross-promo org-wide (stored as a one-way email hash) without touching their primary subscription.
- consent IP + user-agent + timestamp. the consent IP is kept raw (un-hashed) on purpose: it’s the GDPR proof-of-consent record. it’s the one place we hold an un-hashed IP; it’s in the DSAR export and erased on request.
- for pre-save: spotify user id + display name + encrypted refresh token (AES-256-GCM, decryptable only inside the worker process at release-day-fire time).
- a per-row unsubscribe / revoke token.
DSAR: export + erasure.
GDPR Art. 15 (right of access) and Art. 17 (right to erasure). two paths: anyone can go to yala.la/dsar and submit their email + the action; we send a verification link, they click, the action runs across every workspace that holds their data. admins fulfil per-workspace requests from workspace → settings → privacy:
- export: type the person’s email, click export. yala downloads a structured JSON file with every email-capture row + every pre-save row tied to that email in your workspace. you hand it to them via whatever channel you verified the request through (support email, signed letter, etc).
- erase: soft-deletes both rows + redacts PII (email, first name, consent IP/UA, refresh token overwritten with [erased]). aggregates (release-day blast counts) stay; the data subject is gone.
both actions are also exposed via the public API; see public API + webhooks.
analytics events.
IPs are SHA-256 hashed and truncated to 24 bytes at the edge worker. the original IP never leaves the worker; only the hash lives in postgres. that means:
- for analytics we don’t store raw IPs, only the hash, kept solely for bot + abuse detection, never to identify a person. (the consent-trail IP above is the sole exception, a deliberate GDPR record.)
- we can’t enumerate analytics events by a person’s email; the two are not joined.
- DSAR for analytics events is therefore "we don’t hold identifiable data here." that’s the GDPR-correct answer.
cookies + consent.
landing pages drop cookies only when retargeting pixels are configured for the workspace AND the visitor accepts the consent banner. every visitor sees the banner; nothing tracking fires until they choose. consent state is stored in a first-party cookie scoped to the landing.
subprocessors.
- cloudflare: edge redirect engine + KV + custom-domain SSL. handles every redirect.
- vercel: hosts the app, landing pages, and marketing site. landing requests (incl. IP) reach it.
- supabase: postgres + auth + storage. holds workspace + link + analytics data.
- fly.io: background worker (DSP scans, release-day email, pre-saves).
- upstash QStash: async event ingest queue.
- postmark: auth, transactional + broadcast email.
- anthropic: powers the link scan + the publish-time safety check. sees the URLs you paste, never your audience’s PII.
- brave search: the scan’s web-search fallback for platforms without an API.
- stripe: billing. card data never touches our servers.
- meta + tiktok: only when a workspace turns on retargeting pixels AND the visitor accepts the consent banner; then their pixel/CAPI receives that visitor’s IP + user-agent.
security in plain english.
- all traffic is TLS. no plaintext on the wire.
- API keys are hashed; refresh tokens are envelope-encrypted; passwords are hashed by supabase.
- row-level security is on for every public table; we use a BYPASSRLS service role server-side, never the public anon key for anything sensitive.
- a security report? email security@yala.la. we read every report. honest disclosure = honest fix.