Short answer: before you write a policy, go and read your own delete code. Ask an AI coding tool to add delete, and it very often writes an update that hides the row. It sets a flag like deleted_at and moves on. The app stops showing the user. The database still holds them. Under Article 17 you still hold their data, so the request is not met. Fix the delete first. Then chase every copy the row left behind.
We have run more than 700 audits of AI-built SaaS, websites and apps. Erasure fails the same way as the rest. The button works. The data stays.
What Article 17 actually says
A person can ask you to erase their personal data. You must act without undue delay. But only when one of six grounds applies. The common ones for a small product are simple.
- You no longer need the data for the reason you collected it.
- You relied on consent, and they have taken that consent back.
- You relied on legitimate interests, they object, and you have no stronger reason to carry on.
- You used the data for direct marketing, and they object.
- You processed the data unlawfully.
- A law says you must erase it.
Two limits matter here, and most guides skip both.
The first is time. The right covers the data you hold when the request lands. It does not reach forward to data made later. That sounds like a let-off. It is really a warning about order. Turn off the feeds that will re-create the person before you delete them. Otherwise a nightly sync pulls them back, and the next request starts again.
The second is form. A request does not have to be written. It can be spoken. It can arrive in a support chat, a reply to a billing email, or a direct message. It does not have to say “Article 17” or even the word erasure. If you are a small team, any inbox you own is a front door. So the first fix is not code. It is deciding where these land and who reads them.
The clock, and how to count it
You have one month. It starts the day the request arrives, working day or not. Count to the same date in the next month. A request on 3 September is due by 3 October. If the next month is short, you get its last day: 31 March becomes 30 April.
You can take two more months if the request is complex, or if the person has sent several. You must tell them inside the first month, and say why.
The clock can start later in two cases. If you reasonably doubt who they are, it starts when their proof arrives. If you are allowed to charge a fee, it starts when the fee arrives. Both are narrow. Asking for identity proof you do not need is a way to lose the argument, not win it.
If you say no, you still owe them an answer in the same month. Give the reason. Tell them they can complain to a supervisory authority. Tell them they can go to court. Silence is the worst option available.
For a build, the ICO makes a useful practical point: if your system needs a fixed number of days, use 28. That always lands inside a calendar month.
The delete button that does not delete
Here is the part that is specific to how these apps get built. You typed a sentence. A tool wrote the schema, the endpoint and the button. Nobody reviewed what delete meant. Three patterns come up again and again.
1. The soft delete
The endpoint runs an update, not a delete. It sets deleted_at, or is_deleted, or status = 'deleted'. Every screen then filters those rows out.
This is a fair product choice. It guards against a mis-click. It lets people undo. It is also, on its own, not erasure. Holding data is processing it. The name, the email and the message history are all still there. So a soft delete is only a first step. Something must come along later and remove the row for real. In most AI-built apps, that second job was never written.
If you keep the soft delete, keep it deliberately. Pick a short window, say 14 or 30 days. Say so in your privacy notice. Then have a job that purges on schedule, and check that the job actually runs.
2. The missing cascade
Your user row has children. Comments, messages, uploads, invites, notification rows. Each one may carry a name, an email or a note about them.
A foreign key needs to say what happens when the parent goes. ON DELETE CASCADE takes the children with it. Without it, one of two things happens. The delete fails, because the database refuses to orphan the rows. Or the parent goes and the children stay, now pointing at a user who is gone. Those orphan rows are the ones people forget. They are also the ones that still hold the email address.
So map your tables before you trust your endpoint. For each table that names a person, pick one of three. Delete it with the parent. Keep a cut-down version. Or keep it whole, for a reason you can write down.
3. The policy that hides instead of removes
Row-level security is a rule in the database about who may read a row. Many AI-built apps use it well. Some use it to make delete look real.
A policy that filters out rows where deleted_at is set makes those rows vanish from the app. Nothing about the row itself has changed. It sits in the table. It sits in every backup taken since. It is one policy edit away from being readable again. Hiding is not removing. A rule that controls reading cannot satisfy a duty to erase. You can check the read side of this yourself with our Supabase RLS checker.
Every place one user still lives
This is the part founders underrate, and there is a law behind it. Article 19 says you must tell each recipient you gave the data to that you have erased it. The only escape is if that proves impossible or takes disproportionate effort. And if the person asks who those recipients were, you must tell them.
Recipient is a wide word. It covers your processors, not just other companies acting for themselves. That means your vendors. So the list you never wrote down is now something a user can ask you to produce.
Work through these in order. Write what you find in one table: where the copy is, what it holds, who controls it, and how you remove it.
- Your own tables. The user row, and every child row that names them. Include join tables and old tables you stopped using but never dropped.
- Your app logs and error logs. Most AI-written code dumps the whole request, or the whole user, when something fails. That writes emails and tokens into a log store. It keeps them on its own clock.
- Your analytics and session tools. If you tag users by email or user ID, each tool has its own delete route. Find it before you need it.
- Your mail sender. Contacts, lists, and the full text of past emails. Deleting a contact does not always delete the send history.
- Your billing vendor. Treat this one differently. See the exemptions below.
- Search or vector indexes your app writes to. If you built search or a help bot over user content, that content was copied out. It does not clear when the source row goes.
- File and image storage. Avatars, uploads and exports. These sit outside the database, so a cascade never reaches them.
- Caches, queues and read replicas. Short-lived, but not always as short as you assume. A failed job can sit in a queue for days with the payload intact.
- Backups and point-in-time recovery. Its own problem, below.
If your vendors sit outside the EEA, each is also a transfer question. We cover that in our guide to GDPR international data transfers for AI-built apps. The vendor list you build here is the same list you need there. Build it once. And if you have not yet written down what data you hold at all, start with GDPR data mapping for AI-built apps.
Backups, answered honestly
You cannot usually reach into a backup and cut one row out. Backups are often written once and locked on purpose. That is what makes them trustworthy.
The ICO is clear that this does not excuse you. A valid request means taking steps for backups as well as live systems. What those steps are depends on your setup and your retention schedule.
Its test is to put the backup data beyond use. In plain terms: do not use that backup for anything else. Hold it only until your normal cycle replaces it. Let it be written over then. Do that, and the ICO says the remaining copy is unlikely to pose a real risk, though it depends on the case.
Three things follow for a real product.
You need a retention schedule to point at. Beyond use assumes the backup gets replaced. Keeping backups forever, with no cycle, removes your own defence. Set a window. Write it down. Check it matches what your host is set to do.
You must not restore the person back into production. If you recover from a backup taken before the deletion, the row returns. So keep a short list of completed erasures and re-apply it after any restore. This is the step almost everyone misses.
You have to tell the person. The ICO asks you to be absolutely clear about what happens to their data when you fulfil the request, backups included. So your confirmation message should say it: removed from live systems now, and remaining backup copies are not used and drop out within your retention window. One sentence. It also makes the promise honest. Related reading on getting the storage side right in the first place: database backups for AI-built apps.
The audit log problem
Here is a knot worth naming. You should be able to show that you handled the request. The rules ask for that. But a record saying “erased all data for sam@example.com on 12 March” is itself personal data about Sam. You have kept them in order to prove you did not.
The way out is to keep the proof without the person. Record the request reference, the dates you received and completed it, which systems you cleared, and who signed it off. Replace the identity with a one-way hash of the email, or an internal reference you can match if they come back. You keep an audit trail. You do not keep a mailing list of people who asked to leave.
Two notes. Keep that record only as long as you need it to answer a complaint. And make sure your deletion list, the one you re-apply after a restore, uses the same hashed form.
When you can say no
The right is not absolute. Article 17(3) sets out where it does not apply. You may keep the data where you need it for these reasons.
- Freedom of expression and information.
- Complying with a legal obligation, or a task carried out in the public interest.
- Public health, in the narrow cases GDPR lists.
- Archiving in the public interest, or research or statistics, where erasing would seriously damage that work.
- Establishing, exercising or defending legal claims.
For a small product, two of those do the heavy lifting. Tax law tells you to keep invoices, so your billing records stay. And a live dispute or refund claim lets you hold what you need to defend it. This is why the honest answer to “delete everything” is often partial. You erase the account and its content. You keep the invoice. You say which, and why.
You can also refuse a request that is manifestly unfounded or excessive. Read those words narrowly. They cover the person who offers to drop the request for a discount. Or the one who files a fresh request each week to cause trouble. They do not cover a request that is just awkward. Nor a repeat, where you handled the first one badly. You carry the burden of proving it. So decide case by case, and never by blanket rule.
An erasure runbook you can actually run
Order matters more than speed here. Steps four and eight are the ones that get skipped.
- Log it and start the clock. Record the date it arrived. Note where it came from, including a chat message or a call.
- Check who they are. Only if you have real doubt. Ask for the least that settles it.
- Decide the scope. Which grounds apply. What you must keep under Article 17(3). Write the reason next to anything you keep.
- Stop the inflow first. Pause any sync, import or webhook that would re-create the person. The right covers today's data, so a delete followed by a re-import wastes the work.
- Delete at the source. Remove the user row and everything that should go with it. Confirm the cascade behaved, by querying the child tables rather than by trusting the code.
- Fan out to vendors. Walk the list from the section above. Use each vendor's own delete route.
- Handle backups by policy. Apply your beyond-use position. Add the record to your post-restore deletion list.
- Notify recipients. Article 19. Tell the parties you passed the data to. Keep a note of who you told, in case the person asks.
- Write the proof, without the person. Reference, dates, systems, sign-off, hashed identity.
- Confirm in plain words. What you removed, what you kept and why, and what happens to backups.
Run it by hand once, before you automate it. That first run is where you find the table nobody remembered.
What a scan can see, and what it cannot
Being straight about this matters more than the sales pitch. Our Compliance Score runs checks against your live URL and your public policy documents. Two are directly relevant here. Data rights mechanisms (delete, export) looks for whether a delete route exists and can be reached at all. Privacy policy completeness looks at whether your published notice covers what it needs to.
That is the outside view. It tells you if the front door exists. It cannot tell you what happens behind it.
No external check can see your deleted_at columns. It cannot read your foreign key rules. It cannot see how long you keep backups, or logs. It cannot see your queue. It cannot see which vendors hold a copy. Those need a person reading the schema and the dashboards. That is the work in a Launch Readiness Audit Report, a one-time review at $499, checked and signed off by a senior security engineer.
Anyone who tells you a URL scan proves your deletion works is selling you something. The row is either gone or it is not, and only the schema knows.
Find out what your app is still holding
Free Launch Readiness Score in about a minute. No code access needed.
Run a free scanWhat to read next
Erasure is one of a set. The request to see the data is Article 15, covered in our DSAR checklist, and it usually arrives from the same people through the same inbox. Deciding what not to collect in the first place is privacy by design, which is the cheapest version of this whole problem. If a copy leaks rather than lingers, the clock is far shorter: see breach notification in 72 hours. And your vendor paperwork sets what each of them must do when you ask them to delete, which is why it is worth checking your DPAs with AI coding tools before you need them.
FAQ
Does a soft delete satisfy the GDPR right to erasure?
Not by itself. A soft delete sets a flag, such as deleted_at, and the app stops showing the row. The row is still in your table, so you are still holding that person's data. Storing data counts as processing it. A soft delete is fine as a first step, and it protects people from a mis-click. It only becomes erasure when a second job removes the row for real. Pick a short window, say 14 or 30 days, write it in your privacy notice, and check the purge job actually runs.
Do I have to delete a user's data from my backups?
You have to take steps, but not always by cutting the row out at once. The ICO's position is that you should put the backup data beyond use. That means you do not use that backup for anything else, you hold it only until your normal schedule replaces it, and you let it be overwritten then. Two things go with that. You need a real retention schedule to point at, because keeping backups forever removes your defence. And if you ever restore from an older backup, you must re-apply the deletion, or the person comes back.
How long do I have to respond to an erasure request?
One month, counted from the day the request arrives. You count to the same date in the following month, so a request on 3 September is due by 3 October. If the next month has no matching date, you get its last day. You can take two further months when the request is complex or the person has sent several, but you must tell them within the first month and explain why. If you are building this into a system and need a fixed number, the ICO suggests 28 days, which always lands inside a calendar month.
Do I have to tell my vendors that I deleted someone?
Yes, in most cases. Article 19 says you must tell each recipient you disclosed the data to that you have erased it, unless doing so is impossible or takes disproportionate effort. Recipient is broad and includes your processors, which means the vendors acting on your behalf. If the person asks you who those recipients were, you have to tell them. That is why the vendor list is worth writing down before a request arrives, rather than reconstructing it under a one-month deadline.
Can I refuse to delete a customer's invoices?
Usually yes. Article 17(3) lists cases where the right does not apply, and two matter for most products. You may keep data you need to comply with a legal obligation, and tax law generally requires you to keep invoices for several years. You may also keep what you need to establish, exercise or defend a legal claim, which covers a live dispute or refund. So the honest answer to a delete-everything request is often partial: the account and its content go, the billing record stays. Say which parts you kept and why.
How do I prove I erased someone without keeping their data?
Keep the proof and drop the identity. Record the request reference, the date it arrived, the date you finished, which systems you cleared, and who signed it off. Instead of storing the email address, store a one-way hash of it, or an internal reference you can match if the person contacts you again. You then have an audit trail that shows the request was handled, without holding a list of people who asked to leave. Use the same hashed form in the deletion list you re-apply after any backup restore.
Research sources
- GDPR-info.eu — Art. 17 GDPR — Right to erasure (‘right to be forgotten’), reference for the six grounds in Article 17(1) and the exemptions in Article 17(3).
- GDPR-info.eu — Art. 19 GDPR — Notification obligation regarding rectification or erasure, reference for the duty to tell each recipient, and to name them to the data subject on request.
- GDPR-info.eu — Art. 12 GDPR — Transparent information, communication and modalities, reference for the one-month deadline in Article 12(3), the two-month extension, the fee rules in Article 12(5) and the identity check in Article 12(6).
- ICO — Right to erasure, regulator guidance; reference for the backup ‘beyond use’ position, the duty to be clear with people about what happens to backups, the calendar-date counting examples, the 28-day practical suggestion, and the manifestly unfounded and excessive tests. The ICO notes this guidance is under review following the Data (Use and Access) Act.
- GDPR-info.eu — Art. 4 GDPR — Definitions, reference for ‘processing’ including storage, and for the definition of ‘recipient’.
- GDPR-info.eu — Recital 66 — Right to be Forgotten, reference for the intent behind strengthening erasure in the online environment.
- Jai Mittal, Founder & CTO, Launch Ready Code — Proprietary data from 700+ AI-built app security audits, 2025–2026. Average Launch Readiness Score: 44/100.