How We Built a Face Swap Tool That Doesn't Keep Your Photos
Most AI photo tools upload your images into a black box. Here's how we built one that can't see, store, or misuse your data, even if we wanted to.
Most tools that touch your photos are black boxes. You upload. Something happens. You get a result. You have no idea whether the server kept a copy, trained a model on it, or stored it in a bucket that some intern forgot to lock down three years ago.
Swap Dat Face was built to be a different answer to that question. Not "trust us." It is "here's how it works, and here's how you can check."
This is the engineering story behind that.
Why Privacy Had to Be in the Architecture, Not the Privacy Policy
A privacy policy is a legal document. It says what you promise to do. An architecture says what you can do, and what the system physically prevents you from doing.
If your pipeline writes uploads to a public S3 bucket and your privacy policy says "we delete your data after processing," those two facts are in tension. The path of least resistance wins. Someone on the team forgets to run the cleanup script. A misconfigured IAM role leaves objects readable. A contractor copies a dataset "just for testing."
The only privacy that holds up under scrutiny is the kind you build into the system so deeply that breaking it would require rewriting core infrastructure.
So we started from the other end: what would the system look like if the operator was actively hostile to user privacy but the architecture wouldn't let them violate it?
The Data Flow: Upload to Deletion in Under 15 Minutes
A photo takes this path through the system, end to end.
Upload. A file hits the API via a browser. It goes through Cloudflare first for DDoS protection and Turnstile verification, then lands at the Next.js API layer. The API validates the file type and size, generates a unique ID, and writes it to Backblaze B2 object storage with server-side encryption at rest.
Processing. A GPU worker picks up the job from Redis. It fetches the source and target images from B2, runs face detection to build the selection UI, and executes the face swap. The output gets written back to the same private B2 bucket.
Delivery. The result is served to the browser via a presigned URL. A temporary, cryptographically signed link that grants read access to exactly one object for a limited time. After one hour, the URL expires and the object is inaccessible, even if someone has the raw link.
Deletion. A cron job runs approximately every 14 minutes. It scans for objects that have exceeded the retention window and deletes them. The default window is 30 minutes from upload.
There is no CDN in front of the storage. No caching layer. No intermediate server holding copies. Uploads go to B2. Results come from B2 via presigned URLs. Everything else is compute that holds nothing after the job completes.
The Retention Log: Trust Through Verification
Promising to delete data is easy. Proving it is harder.
Swap Dat Face runs a retention log at /api/retention that is cryptographically signed with an Ed25519 key. The log includes the policy values (max retention, cleanup interval), the timestamp of the last cleanup run, and the age of the oldest remaining object. The signature is verifiable using the published public key at /api/retention/signing-key.
This matters because it removes the need for shared secrets. Anyone can verify the log independently. You do not need to trust us. You can check. The source code is open at github.com/swapdatface/retention-log.
The log does not expose individual filenames. It provides operational evidence: here is when we last ran cleanup, here is how old the oldest object is, here is a cryptographic proof that this report was generated by the key that belongs to the service. If the oldest object is 3 minutes old, the log says so. If it is 3 days old, the log says that too, and you would know something is wrong.
What We Deliberately Do Not Store
Some architectural decisions are about what you build. Others are about what you refuse to build.
The system does not store face embeddings. Face detection runs in the worker to power the selection UI, but the embeddings are discarded after the swap completes. There is no database of "who looked like what."
The system does not store personally identifiable information. Free users are identified by a browser hash that auto-expires after 24 hours of inactivity. No email. No name. No account. Redis forgets inactive users without any cleanup required from our side.
The system does not use uploaded photos for training. The images go into B2, get processed, and get deleted. There is no pipeline that feeds them into a training dataset. No "we might use your data to improve our models" clause buried in the terms. The code simply does not have the machinery to do it.
The system does not make storage buckets public. Every object is private by default. The only way to access a result is with a time-limited presigned URL tied to your specific session.
These are not features. They are the absence of features, and that is the point.
The Free Tier: What "No Account Required" Costs
Building a privacy-first tool means choosing where to draw lines. The free tier draws a specific one: 3 swaps per 24 hours, no account required, 30 minute automatic deletion.
The rate limit is enforced by browser identifier. This is not a perfect solution. Browser fingerprints can change, VPNs can rotate IPs. It is the right tradeoff for a system that does not collect PII. The alternative is requiring an email address before the first swap, which defeats the purpose.
Paid users get an account, a credit ledger, and the option to enable extended retention of up to 30 days. The retention preference is stored at the account level and applied at processing time. This means a paid user can choose to keep their GIFs and videos for later, while free users are always on the 30 minute default.
The architecture page has the full breakdown of what each tier includes, alongside the technical details of how abuse prevention works across both.
The Hardest Part Is Not the AI
The face swap model is not the hard engineering problem here. Plenty of models do face swapping. The hard problem is building a pipeline around it that you can look someone in the eye and say "your data is gone, and I can prove it."
That means designing for deletion from day one. Choosing object storage over CDN caching even though it costs a bit of latency. Writing a cron job that runs 100 times a day and publishing its output with a cryptographic signature. Refusing to build the data collection features that every product manager would ask for.
The result is a face swap tool where the operator's access to your photos is both time-limited and verifiably terminated. Not because a policy says so. Because the code makes it true.
Frequently Asked Questions
How long does Swap Dat Face keep my photos? Free photo swaps are deleted within 30 minutes. Paid jobs default to the same 30 minute window, with optional extended retention of up to 30 days if you enable it in your account settings.
Can I verify that my photos were actually deleted? Yes. The retention log at /api/retention is cryptographically signed with an Ed25519 key. Anyone can verify the payload using the published public key at /api/retention/signing-key.
Do you train AI models on user photos? No. We do not train models on uploaded images, build datasets, or store face embeddings. The only thing that happens to your photos is the face swap you asked for, and then they are deleted.
Where are uploaded photos stored? Uploads go to Backblaze B2 object storage with server-side encryption at rest. There is no public-facing CDN in front of the storage. Results are delivered to you via time-limited presigned URLs that expire after one hour.
Do I need an account to use Swap Dat Face? No. Free photo swaps use a browser identifier for rate limiting only. No email, no password, no PII collected. Paid features require an account for credit tracking and retention preferences.
Ready to try it?
3 free swaps daily. No signup required.