Who holds your data

Framevane is software that runs on a server somebody installs and operates. There is no Framevane service in the middle: whoever runs this instance holds the database, the recordings and the platform credentials on it, and is the data controller for everything described here.

This page describes what the software does with data, so that an operator can hand it to their own users and so that the people whose accounts are connected to it can see where their information goes. It does not describe the practices of any platform you broadcast to; those are governed by YouTube, Meta and TikTok respectively.

Operator contact: [email protected]

Write here to ask what is held about you, to have it deleted, or to have a recording removed from the server.

What this server stores

All of it lives in the Postgres database on the server, except the recordings, which are files on the same machine.

Your account — name, email address, and either a password hash or a link to the GitHub or Google account you signed in with
Signing in. Nothing else reads it.
Sessions, including the IP address and user agent of the browser that signed in
Keeping you signed in, and showing you where a session came from.
Streams: the ingest key, the control token, and the settings — mode, visibility, resolution, bitrate, overlay timings
The ingest key is what the phone publishes to. The control token is a separate credential so a lost phone can be revoked without knocking every encoder pointed at that stream off the air.
Destinations: the platform, the RTMP URL and the stream key
The compositor is handed these per broadcast; it keeps no database of its own. Stream keys are stored so a broadcast can start without you pasting one, and the dashboard never returns a full key to the browser — only its last four characters.
Platform connections: the platform’s own account id and display name, the granted scope, and the OAuth access and refresh tokens
So Framevane can fetch an ingest key and open and close the live event for you. The tokens are encrypted — see below.
Overlay presets: whatever text you save into the slots
Name cards and tickers you reuse.
Broadcast history: start and end times, mode, restarts, the last error, and the platform events that were opened with their watch URLs
So a finished broadcast can be reviewed, and so an event opened on a platform can be closed again when the phone stops.
Recordings: an MP4 per broadcast, on the server’s own disk
The archive. It is written where the stream is processed rather than uploaded anywhere.

How the tokens are protected

A platform refresh token is not a stream key. A stream key lets someone broadcast to one channel until it is rotated; a refresh token is standing access to the account itself. So access and refresh tokens are sealed with AES-256-GCM before they are written and opened only in memory, when a request needs them. The key is derived with HKDF-SHA256 from the instance’s BETTER_AUTH_SECRET under a distinct label, so it is independent of the key used for sessions. A database dump on the wrong disk therefore does not hand over anybody’s channel.

Stream keys and ingest keys are stored unencrypted. They are credentials for one channel, they are rotatable, and the compositor has to be handed them in the clear to broadcast at all — encrypting them at rest with a key held on the same machine would be theatre. Treat the database, and the pairing QR code, as secrets.

What leaves the server

  • The broadcast itself, to each destination you have added, for as long as you are live. That is the purpose of the software.
  • API calls to the platforms you connect — the YouTube Data API and Meta’s Graph API — to read a channel, create an ingest endpoint, open, bind and end a live event, and read its status.
  • Audio, only if you switch captions on. With captions set to transcribe or translate, four-second segments of the broadcast’s audio are sent to Groq’s Whisper endpoint and the returned text is drawn on the picture. Each segment is deleted from the server once it has been transcribed. Captions are off by default and do nothing at all unless the operator has configured a Groq API key.
  • A font request from your browser. These public pages load Archivo, Source Serif 4 and IBM Plex Mono from Google Fonts, so your browser contacts fonts.googleapis.com and fonts.gstatic.com. That is the only third-party request any page here makes.

There is no analytics, no tracking pixel, no session recording and no advertising code anywhere in this application. The pairing QR code is rendered on the server by a library in the repository rather than by a QR service, because a pairing code carries a live credential.

Google user data

Connecting YouTube requests one scope, https://www.googleapis.com/auth/youtube. The read-only scope would be enough to fetch a stream key but not to put a channel on air, which is the feature.

Framevane uses the access it grants to do exactly five things:

  • read the connected channel’s id and title, so the dashboard can show you which account is connected;
  • read or create the channel’s ingest endpoint and its stream key;
  • create a live broadcast when you go live, with the visibility set on the stream;
  • bind that broadcast to the ingest endpoint and transition it live, then complete it when the phone stops;
  • poll the broadcast’s status and the stream’s health while it runs, so the studio can tell you what YouTube thinks of the feed.

Google user data obtained through this scope is not sold, not transferred to anyone, not used for advertising, not used to train any model, and not read by a human. It is used solely to operate your own broadcasts on the instance you connected it to, and it never leaves that server except in the API calls above. Framevane’s use of information received from Google APIs adheres to the Google API Services User Data Policy, including the Limited Use requirements.

You can disconnect the account from the dashboard at any time, which deletes the connection row and the sealed tokens with it, or revoke access from your Google account permissions. One caveat worth stating plainly: a destination created from a connection keeps its own copy of the stream key, so disconnecting stops Framevane managing the events but does not stop an existing destination broadcasting. Delete the destination to stop that.

The same applies to a Facebook connection, which stores the Page it was authorised for and its token under the same encryption.

Cookies

One cookie, set when you sign in, holding your session. It is cached for five minutes to avoid a database read on every request. There are no analytics or advertising cookies, and nothing is set for a visitor who does not sign in.

Keeping and deleting

Nothing here expires on a schedule. Deleting an account removes its streams, destinations, presets, broadcast history and platform connections with it, in the database. Recordings are files and are not deleted with the rows that point at them — deleting an account leaves its recordings on the server. They are kept to a size budget, and once the archive exceeds it the oldest recordings are deleted to make room, so a recording will not live forever unless the operator has turned that budget off. Nothing is offloaded anywhere else. Ask the operator of this instance to delete a recording, or delete it on the server.

Database backups are not configured by the software. If this instance has them, that is the operator’s arrangement and their retention applies.

Security, honestly

Transport security is whatever the operator configured. The dashboard is meant to be served over HTTPS, and an instance reachable from the internet should be — but a studio on a LAN with no certificate is a supported deployment, and on that network the control token travels in the clear. The phone’s control credential is separate from the ingest key and separately revocable for exactly this class of reason.

Nobody can promise a system is secure. What can be said is where the boundaries are: platform tokens are encrypted at rest, the control API compares tokens in constant time and never logs or returns them, and an unknown token is answered identically to a real one with nothing to say, so the endpoint cannot be used to discover which tokens exist.

Changes to this policy

This page changes when the software does. It is part of the source and is changed in the same commit as the behaviour it describes, so updating an instance brings the policy and the code it belongs to together. The technical detail behind everything above is in PLATFORMS.md, and the shape of the system is on the docs page.