How to Delete Customer Data From Your AI Stack
Deleting a customer from an AI system is not one DELETE statement, because the stack has already made derived copies in a vector index, an execution log, a provider-side file store, and sometimes a fine-tuned model. Sort every copy into one of three groups by the verb it supports (delete now, expire on a schedule, or cannot be removed at all), then confirm the expiry schedules are shorter than your statutory deadline before a request ever arrives.
A customer asks you to delete their data. You run the DELETE on the row, and you are maybe a third of the way done. An AI stack makes derived copies as a side effect of working: an embedding in a vector index, a full payload in an automation execution log, an uploaded file sitting in a provider's storage, sometimes a record folded into a fine-tune. The useful move is not a longer checklist of places to look. It is sorting every copy by the verb it actually supports, because only some of them support the verb "delete."
The six copies a deletion request has to reach
Before arguing about mechanics, get the inventory right. A modest retrieval chatbot with a lead-capture workflow behind it produces all of these from one customer interaction.
| Where the copy lives | What "delete" does there | Worst case time to actually gone |
|---|---|---|
| Your primary database row | Removes it | Immediate |
| Vector index chunk and its embedding | Usually sets a tombstone flag; the float array stays in the index file | Next compaction or index rebuild |
| Automation execution history (n8n, Zapier, Make) | Removes the run record if you can find it, otherwise waits for the purge | Zapier default up to 69 days; n8n default 14 days, but never for annotated runs |
| Model provider request logs | Nothing you can call | About 30 days, longer if the content was flagged |
| Provider-side stored objects (files, vector stores, fine-tuning jobs, evals) | Deletes, but only if you call the delete endpoint yourself | Indefinite. These are not on the 30-day clock |
| Fine-tuned weights and eval fixtures built from real records | Nothing | Only a retrain or a rebuilt fixture |
Six rows, three different verbs. Row one supports delete. Rows two, three, and four support expire. Rows five and six are a trap in opposite directions: five looks automatic and is not, and six is not removable at all.
Sort every copy into delete, expire, or never
This is the part the standard guides skip. They give you a list of systems and tell you to cascade the deletion across all of them, which reads fine until you try to write the confirmation email.
Delete means you issue a call and the data is gone when it returns. Your database row, a CRM record, an S3 object. You can tell the customer it is done, and you can prove it.
Expire means you can stop new writes and shorten the window, but existing copies leave on a schedule you do not fully control. Vector index tombstones, execution history, provider request logs, backups. For these you cannot honestly report "deleted" on day one. You can report a date. Which means the only thing that matters is whether that date lands inside your statutory deadline, and that is a decision you make when you configure the system, not when the request arrives.
Never means the data is baked in. A fine-tuned model has no per-record delete. Neither does the golden test set someone assembled last spring out of 200 real support tickets, or the summary table where a customer's numbers were folded into an average. For "never" copies there is exactly one control, and it is upstream: do not create them out of identifiable customer data in the first place.
Run your own inventory through those three buckets. Every row that lands in "expire" needs a configured window shorter than your deadline. Every row that lands in "never" is a design decision you should revisit before you get the request, not after.
The embedding is not anonymous, so treat it as personal data
A common assumption is that once text becomes a list of 1,536 floats it stops being personal data, so a vector left behind is a housekeeping issue rather than a privacy one. That assumption does not survive contact with the literature.
The vec2text work presented at EMNLP 2023 inverted embeddings back into their source text, recovering 92 percent of 32-token inputs exactly, and pulled full names out of a corpus of clinical notes. An embedding is a lossy but largely reversible encoding, not a one-way hash. If the chunk said "Maria Delgado, account 44817, disputed the March invoice," the vector still says that to anyone with the right decoder.
Then there is what "delete" does inside the index. A June 2026 preprint on HNSW-backed stores put the problem plainly: soft delete is a deliberate design trade-off, not a bug. Deleting a record sets a metadata flag so queries skip it, and the vector itself stays physically unchanged on disk. The authors tested Chroma, FAISS, and embedded Weaviate, read the raw index files past the API, and recovered 25.5 percent of person names and 46.4 percent of geographic locations from Wikipedia biography embeddings, plus 100 percent of age and gender markers from synthetic health records. FAISS IndexHNSWFlat, they note, offers no delete method at all.
Practically: a delete call is enough to stop your bot citing the customer, which is the stale retrieval problem. It is not enough to claim erasure. For that you need a compaction, a namespace drop, or a rebuilt index, and you should know which of those your engine supports before you promise anything. If you are still choosing a store, this belongs in the evaluation alongside recall and cost, and it is one of the things we check when we build a retrieval system as part of a custom AI platform.
Your automation history probably outlives your legal deadline
Here is the collision nobody puts in writing. Under the CCPA you have 45 days from a verifiable request. Zapier's default is to retain Zap history for 29 to 69 days, because it deletes on a monthly cycle rather than a rolling one, and shortening that window to between 7 and 30 days is an Enterprise-plan setting. So on a standard plan, the default retention of the tool holding the full payload of every step can outrun the deadline for erasing that payload.
You can delete individual runs by hand from the Zap history page, which is the escape hatch. There is no query for "every run containing this email address," so at any real volume that is a hunt, not a procedure.
Self-hosted n8n is better positioned and has its own edge case. Pruning is on by default at 336 hours, which is 14 days, or 10,000 executions, whichever hits first. Comfortably inside 45 days. But annotated executions, the ones a developer tagged or rated while debugging, are never pruned. The runs most likely to be starred are the ones that went wrong, which are the ones carrying the messiest real customer data. Those sit in your database forever unless someone removes them deliberately. We wrote separately about how execution logs quietly hold more PII than your database; a deletion request is where that bill comes due.
The provider side has the inverse shape. OpenAI and Anthropic both publish roughly a 30-day window for API request logs, which is why people assume the provider handles itself. But OpenAI's own documentation is explicit that stored objects are different: files, vector stores, fine-tuning jobs, evals, and conversations are retained until deleted. Every PDF your workflow uploaded to build a knowledge base is still there. Nothing expires it. That endpoint has to be on your runbook by name.
None of this is optional housekeeping, either. California Civil Code 1798.105(c) requires the business to notify its service providers and contractors to delete the consumer's information and to pass the request on to third parties it sold or shared with. Your vector host, your model provider, and your automation platform are service providers under that language.
Run a deletion drill before a real request arrives
Pick a test customer today. Put them through the full path: a chat session, a document upload, a lead-capture workflow, a knowledge-base ingest. Wait a day so the data settles into every store. Then delete them and time it.
Count two things. How many systems did you have to touch by hand, and what is the longest expiry you are now waiting on. If the manual count is above three, the process will not survive being run by whoever is on duty in November. If the longest expiry is past 45 days, you have a configuration problem you can fix now for free, and cannot fix later under a clock.
The drill also surfaces the "never" copies faster than any document review, because that is the moment someone says the sentence out loud: the eval set has real tickets in it. Better to hear that in a drill than in a response letter. Reducing what enters these systems at all is the cheaper half of the same job, and it starts with stripping identifiers before the data reaches the model. If you want a second pair of eyes on the map before you run the drill, tell us what your stack looks like and we will walk it with you.
Frequently Asked Questions
SOURCES & CITATIONS
- Ghost Vectors: Soft-Deleted Embeddings Remain Reconstructible in HNSW Vector Databases — arXivhttps://arxiv.org/abs/2606.18497
- Text Embeddings Reveal (Almost) As Much As Text — arXiv / EMNLP 2023https://arxiv.org/abs/2310.06816
- Data controls in the OpenAI platform — OpenAIhttps://developers.openai.com/api/docs/guides/your-data
- California Civil Code 1798.105, Consumers' Right to Delete Personal Information — California Legislative Informationhttps://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CIV§ionNum=1798.105
About Alexey Yushkin
Alexey is the founder of GENERAL INFORMATICS LLC. He designs and ships AI and automation systems for businesses and operators across the US.
Related reading
Want this kind of system in your business?
We build practical AI and automation systems for operators. Send us your current workflow and we will show you what to automate first.
Request a Workflow Review