Security
How TipPage looks after the things it is trusted with: the money, the credentials, and the identities of streamers and the people who tip them.
On this page12 sections
What this page is
This is a plain description of how TipPage is engineered and run.
Three principles shape most of the decisions below. Money never passes through us. Anything we hold on your behalf is either encrypted with a key you would also need, or reduced to a one-way hash we could not reverse if we wanted to. And our servers don't accept connections straight from the internet. Traffic comes in through an edge node or a Cloudflare Tunnel, and both reach the cluster over private networks.
If something here is unclear, or you think it is wrong, we want to know: see Reporting a problem.
Where the money goes
Card numbers never touch our servers. The card form on a tip page is served by Stripe, the details go from the tipper's browser straight to Stripe, and Stripe (a PCI DSS Level 1 processor) charges the card. What we receive back is a reference, the last four digits and the card brand: enough to show a receipt and to run the checks described below, never enough to charge the card again.
A card tip is charged by TipPage.com LTD and then transferred to the streamer's own Stripe account, minus Stripe's processing cost and our fee. We do this deliberately, rather than letting each streamer charge cards directly, for a privacy reason: it means the tipper's statement reads TIPPAGE.COM LTD and not the streamer's legal name, and it means Stripe's charge lookup tools show our registered address, not the streamer's home. In the other direction, the streamer never sees the tipper's card details, billing address or email. Neither side can look the other up.
A card tip is authorised first and captured second. The hold placed when the tipper confirms is where every check runs: if the payer turns out to be banned, the hold is released and no money moves. If a streamer has the review queue on, the hold simply stays open until a moderator decides, and a rejected tip is never charged at all.
PayPal is different, and we say so on the tip page. PayPal tips move directly from the tipper's PayPal account to the streamer's, under PayPal's receipts and rules, so the statement-privacy protection above does not apply to them, and a banned payer on PayPal is refunded after the fact rather than never charged. We never hold streamer funds on either processor.
Credentials and secrets
Connecting a Twitch, Kick or Stripe account gives us OAuth tokens that act on your behalf. Those tokens are encrypted at rest with AES-256-GCM using envelope encryption: each streamer's data is sealed under its own key, and those keys are in turn sealed under a master key that lives outside the database. A copy of the database on its own is not enough to read a single token. Viewers who sign in on a tip page get the same treatment under a separate key.
Developer API keys are never stored. We keep a SHA-256 hash, show the full key exactly once when it is created, and can check a key without being able to read it back. There is no way to reveal an existing key, only to rotate it from the dashboard, which is also why a leaked key cannot be used to mint a replacement. OAuth app secrets are stored the same way, and the authorisation flow for third-party apps is authorisation code with PKCE (S256 only), with exact-match redirect URIs.
Webhook signing secrets are encrypted per streamer. Service credentials inside the cluster are held in its secret store, are scoped so each service only holds what it needs, and are never in source code or container images.
Backups
Our database and cache are backed up every half hour to Backblaze, in its European data centres, so a failed disk, a bad deploy or an attacker cannot take your tips and settings with them.
Every backup is encrypted by us, on our own servers, before it is sent anywhere. Backblaze encrypts what it stores as well, but that is the second layer: the first is ours, and the keys for it are not held by Backblaze. What Backblaze keeps is data it cannot read. The backups hold the same things the live database does, so the same protections apply to them: tokens are still sealed under their own keys inside the backup, and ban signals are still one-way hashes.
Backups are kept on a rolling schedule and then deleted. Data you delete stays in backups already taken until they expire; a backup is only ever restored to recover from a failure, and when one is, deletions made since are applied again.
Accounts and access
There are no TipPage passwords. Streamers and team members sign in through Twitch or Kick, viewers sign in on a tip page the same way, and we never see or store a password for any of them. Sessions live in cookies that are HttpOnly and Secure, so a script on the page cannot read them, and signing out ends the session on our side, not just in the browser.
Team access is granted per area. A moderator you invite sees only the parts of the dashboard you ticked (the queue, the filter list, moderation, the bot) and nothing else exists for them. Invite links work once and expire after seven days unused. Developer API keys and connected OAuth apps carry explicit scopes, so a key that can read the queue cannot refund a tip or change a setting, and there is deliberately no API scope for payments, members or account settings at all.
The ban engine
The problem it solves is simple to state: on most tip platforms, a person you ban is back two minutes later with a fresh email address and another £2. Blocking one email or one card does nothing against that. So a ban on TipPage is not a single field. It is a growing cluster of identity signals that all point at the same person, and the engine's job is to recognise that person when they come back wearing a different name.
What it compares
Every finished tip leaves behind a snapshot of the identity signals available at the time: the payment method, the signed-in Twitch or Kick account if there was one, the device, and the network the tip came from. When you ban someone, that snapshot seeds the ban with the whole bundle at once, not just the one thing you happened to click on. We do not publish the full list of signals, because that list is precisely what someone trying to get round it would want.
Signals are not all trusted equally. A small set of hard signals block on an exact match by themselves: the same payment identity, the same account, the same device. A second set of soft signals are never enough on their own. They are the kind of thing that can legitimately be shared, such as two people in one house on one connection, or a card and the wallet that is funded by it, so a soft match raises a flag for review rather than blocking a tip. Network signals sit in between: a match is treated as strong for a limited window after a confirmed sighting, because addresses are reassigned, and then degrades to a soft signal on its own.
How it learns
When a hard signal blocks an attempt, the other hard signals in that attempt are added to the ban. Someone who tries a new card from the same device has now taught the engine about the card; someone who tries a new device with the same account has taught it about the device. Each evasion attempt makes the ban wider, which is the opposite of how a simple block list behaves. Soft signals never merge two bans into one and an address match never extends its own welcome, so the engine cannot quietly grow a ban into something that catches bystanders.
Where it runs
The engine runs before money moves. Account and device signals are checked when the tip is submitted, before a payment form is even shown. Payment signals are checked on the card hold, before capture, so a banned payer's hold is released and they are never charged; there is nothing to refund and nothing for them to dispute. The device signal reaches us through a token our own server issues to the tip page and accepts exactly once, so a client cannot assert a device identity of its choosing.
What we store
Nothing readable. Every signal is put through a one-way hash with a salt that is unique to the streamer before it is stored, and the engine only ever compares hashes for equality. What sits in our database can answer one question, "is this the same person this streamer banned", and cannot be turned back into an email address, a card number or an account. Because the salt is per streamer, the same person produces different hashes on different tip pages, so a ban on one streamer cannot be used to identify or follow that person on another. The engine also only ever looks at people who have been banned; everyone else's tip is compared against nothing.
The dashboard's donor profile reuses the same snapshots to show a streamer which of their own past tips came from the same person, with the linking signal named for each. Hashes themselves never leave our servers; the dashboard sees numbered identities, not the values behind them.
Other abuse defences
Fraud screening is separate from bans and runs across every TipPage page, on signals from the payment processor rather than from us. A card that has been used fraudulently on one streamer is blocked for all of them, and disputed payments feed back into that screening.
On what plays on stream: every tip message goes through the streamer's word filter before it can be spoken or shown, and on TipPage+ through an AI pass that reads the message the way a listener would hear it, so a name split into syllables or spelt as a sound-alike is caught rather than read aloud. The model is only allowed to act on entries the streamer actually listed; it cannot invent a block. Streamers who want a person in the loop can hold every tip, or every filter match, for a moderator, with the card hold kept open until they decide.
Every public endpoint is rate limited by client address, with the limits keyed to what the endpoint does. Chat commands, TTS generation and AI replies carry their own per-streamer budgets so a flood in one channel cannot exhaust a shared resource for everyone else.
AI voices
The AI text-to-speech behind TipPage+ voices is a model we run ourselves, on GPUs rented by the second from Modal Labs, not a third-party voice API. Our API dispatches each job and never handles the audio: the worker writes finished audio straight to our CDN through a one-off signed upload address, so a tip's audio passes through one machine, once.
Recordings a streamer uploads to create a voice are sent to the worker through short-lived signed links, never a public URL, and are deleted from our storage as soon as the voice is built - the voice is generated from the worker's own processed reference audio, which lives in a private bucket only the worker and our API can reach. Each voice is addressed by a random identifier; the worker-side identifier never leaves the API. A voice is private to the streamer who made it unless they publish it, and TipPage can take any voice out of service in one call without deleting the history of tips that used it.
Access to the feature is granted per streamer by us, on top of a TipPage+ subscription, and every message spoken by an AI voice goes through the same filter and moderation path as any other tip. A viewer's text can never carry the model's speaker-change markers: they are stripped on the way in, so a message cannot hijack the voice it was not given.
How the servers are reached
Our servers have public addresses, like any servers do, but nothing that serves TipPage listens on them. The gateway that routes requests to our services can only be reached on a private network. Requests get to it in one of two ways.
Most of the platform, including the dashboard, tip pages and this website, goes through a Cloudflare Tunnel: connectors running inside the cluster open outbound, authenticated connections to Cloudflare's edge, and requests for our hostnames travel back down those connections. Cloudflare terminates TLS close to the visitor, absorbs volumetric attacks, and forwards clean requests down the tunnel.
The API and the realtime connections that feed overlays, which are long-lived and sensitive to latency, go through an edge node we run ourselves. It terminates TLS for those hostnames and passes requests on to the cluster over an encrypted private mesh network. It holds no database, no customer data and no service credentials. It sets the visitor's address itself and discards any address a client claims, so rate limits and the ban engine's network signal see the real visitor. If it is ever under attack it can be put behind Cloudflare's protection within minutes.
Traffic between your browser and us is encrypted end to end on both paths, and traffic between our own services stays on private networks and never crosses the public internet. The cluster itself exposes no ports on its public addresses, and administrative access is over the private mesh network, not an open port.
The platform runs on our own Kubernetes cluster as a set of independent services: the tip pages, the payment pipeline, the queues, the chat bot and the realtime tier that feeds overlays are separate deployments, each running as several replicas from immutable images. Any replica can serve any request, shared state lives in the data layer, and a failed machine has its work rescheduled onto its neighbours automatically. Releases are rolling: new code is health-checked before it takes traffic, and overlays keep their realtime connection straight through a deploy.
Outbound webhooks
Every webhook we send to a developer's endpoint is signed with HMAC-SHA256 over a timestamp and the exact body, so the receiver can check that a delivery came from TipPage and is not a replay. The signed body is stored with the delivery, so a redelivery is byte-for-byte identical and verifies against the same signature.
Endpoint URLs are validated before every delivery: private, link-local and internal addresses are refused, DNS is resolved through the same guarded lookup that opens the socket so a rebinding trick cannot change the answer between check and connect, and in production delivery is HTTPS only. Deliveries are relayed through Cloudflare's edge, so an endpoint sees a Cloudflare address rather than our cluster's.
What we don't claim
We do not hold a SOC 2 or ISO 27001 certificate. The design choices on this page are our own, and we describe them so that you can judge them. We rely on Stripe, PayPal, Cloudflare and Backblaze for the things they are better at than we are, and we say where that is the case.
Nothing here is a promise that no incident will ever occur. It is a description of how we have arranged things so that when one does, the blast radius is small: no card numbers to lose, no readable identity data in the ban system, no credentials that are useful without a key we keep elsewhere, and no public ports on the cluster itself.
Reporting a problem
If you believe you have found a security issue in TipPage, email hello@tippage.com. Tell us what you found, where, and how to reproduce it; a proof of concept helps but is not required. We read these promptly, we will keep you updated while we investigate and fix, and we are happy to credit you for the find if you would like.
We will not pursue action against research done in good faith within these rules:
- Test only against your own accounts, pages and data.
- Do not access, modify or disrupt other people's accounts, tips, streams or overlays.
- No denial-of-service testing, no spam, and no social engineering of streamers, tippers or TipPage staff.
- If you stumble into someone else's data, stop, don't keep a copy, and tell us what happened.
Give us a reasonable window to fix an issue before sharing it publicly, and we will work with you on timing.