All posts

How to recover data that was bulk-deleted in a CRM

Somebody ran a bulk operation on the wrong segment, and tags, links or whole records vanished from the list. There is no undo button. But in most cases the data is still there.

FLAGGED — NOT DELETED restored 3 / 6 RECORD DELETED_AT 8412 · tag “client” null 8413 · tag “VIP” null 8414 · tag “client” null 8415 · tag “campaign” 12:40:07 8416 · tag “client” 12:40:09 8417 · tag “VIP” 12:40:12 restore.js --live REQUEST LOG POST /link 201 POST /link 201 POST /link 201 a reverse run of this file — the undo button
Short answer

First find out whether the record has really been deleted. Plenty of systems do a soft delete — the row stays in the database with a flag on it, and it can be brought back with the same method that created it. Then: put together the list of what needs restoring, from a database copy, an export or logs; run it as a dry run that writes nothing; and only then start the live run, logging every request. That same log later works as the undo button.

Sections · 8

A bulk operation was run on the wrong segment. Tags are gone, so are the links between contacts and segments, sometimes the records themselves. There is no undo button in the interface, support often takes a day to reply, and the managers cannot work in the meantime.

In most cases the data has not gone anywhere.

#Deleted, or only marked as deleted

Before doing anything, answer one question: is the record deleted, or marked as deleted?

Soft delete — the row stays in the database, it simply gets a flag on it. Plenty of CRMs work this way, because it is cheaper and safer. Checking is easy: request the object by its id through the API. If a 200 comes back and the data is there, it is a soft delete, and recovery comes down to clearing the flag or recreating the link.

Hard delete — the row is gone. Then your only source is a backup or an export made before the incident.

#Where to get the list of what to restore

You need a list of pairs — what was linked to what — as it stood before the incident. Sources, most reliable first:

  • a database backup — if you have one and it was made before the event;
  • an export from the admin panel — many systems will let you download the links as a table;
  • logs from the operation itself — if whoever deleted the data kept the output of the run;
  • other systems — if the same data is duplicated in another service.

There is less time here than it looks: in some systems, records marked as deleted are physically removed after a few days. So the list comes first, before you write any recovery code.

#Why the dry run is mandatory

By default the recovery script has to do nothing. Only show what it is about to do.

node restore.js                 # sends nothing, prints the first 10 requests
node restore.js --live          # only after you have checked that by eye

The dry run checks three things: the ids are right, the method is right, and the count is right. If the script is about to make thirty thousand requests and three thousand links were deleted, something is wrong with the list, and it is better to see that now.

#Why every request goes into a log

This is the main part, and it is done before the run, not after.

Every request that goes out gets its own line: method, address, body, response code, time. The format is one JSON record per line, so the file can be read in pieces instead of held in memory.

That log gives you three things:

  • proof. You can see exactly what was done, rather than “we think we restored it”;
  • recovery after a failure. The connection dropped halfway — a rerun picks up only what is not in the log file;
  • undo. The same file, run back through with the opposite method, puts everything the way it was.
node restore.js --live --method=DELETE --from-log=logs/2026-08-13.jsonl

That is the undo button the interface does not have. You have to build it yourself, and build it before the live run.

#What to check before the live run

  • Whatever was deleting has been stopped.
  • The list is collected and saved as a file of its own.
  • The dry run showed the expected count and the right method.
  • It has been tried on one record, and the result has been looked over by eye in the interface.
  • The script writes its log to a file, not to the console.
  • You know how to roll it back: the rollback command is written in advance.

The single-record item is the one people skip most often. It costs a minute and shows you the mistake before it becomes a bulk one.

#What to do after the recovery

An incident is closed by removing the cause, not by the recovery.

In some CRMs bulk operations are open to everyone with access to the segments. The minimum that makes sense: narrow down who is allowed to run them, and set a rule that an export of the segment is saved before any bulk action. Those thirty seconds turn the next recovery into a single import.

#Takeaways

  • Stop whatever is deleting first, and only then restore.
  • Check whether it is a soft delete: the data is often still there.
  • Put the list together straight away — flagged records can be removed for good.
  • By default the script writes nothing; the live run sits behind a flag of its own.
  • Every request goes into the log. That same log is the proof, the way to carry on after a failure, and the rollback.
  • Before the bulk run, try it on one record.

#Common questions

#How much time do you have to recover?

It depends on the system. Records marked as deleted can be removed for good after a few days. Assume you have twenty-four hours, and put the list together first.

#Can you recover with no backup?

Often yes — if it is a soft delete, or if the same links exist in another system. If it is a hard delete and nothing is duplicated anywhere, there is nothing to restore from.

#Who should do this — your team or the service’s support?

If there is an API, it is faster to do it yourself: support often takes a day to answer and rarely restores selectively. It is worth going to them when it is a hard delete and you need a copy from their side.

weirflow — Business process automation. Published: August 14, 2026

Describe your situation

Tell us which process eats the most time. We will write back with what can be automated and roughly what it would cost.

Discuss a project
All posts