A full sync is the most reliable way to keep a table in step with its source: read everything, replace the table. It has one side effect people only notice later. When a record is deleted at the source, the full sync deletes it from your warehouse too, and there is no trace it was ever there.
That is fine until someone asks what last quarter's numbers looked like before an invoice was voided, or why a campaign that drove half of March's spend no longer appears in any report. The answer was in your warehouse, right up until the sync that removed it. Capture deletes, now in beta, keeps it there.
TL;DR: Capture deletes (Beta) changes what a full sync does with a row the source stops returning. Instead of removing it, Weld keeps the row and stamps it with a _weld_deleted_at timestamp. It's available today on Google Ads, Microsoft Ads, NetSuite, Microsoft SQL Server and Traede, on the Premium and Business plans, and you turn it on per table.
How Capture deletes works
With Capture deletes turned on for a table, a full sync merges the snapshot it just read into the existing table instead of replacing it. Every row the snapshot no longer contains is marked with _weld_deleted_at, and everything else is updated as usual.
A few details make the column dependable to query:
- The timestamp is recorded once. A row keeps the
_weld_deleted_atit got on the sync that first noticed it was gone, so the value tells you when the record disappeared, not when the latest sync ran. - A record that comes back is unmarked. If the source starts returning the row again, the next sync clears its
_weld_deleted_at. - A partial run only speaks for what it read. If a run covers part of the source, for example some of the ad accounts in a multi-account Google Ads sync, it only reconciles that part and leaves the rest of the table alone. Removing an account from a sync doesn't mark its rows as deleted.
Querying deleted rows
Rows that are still live have a null in _weld_deleted_at, so your existing models need one filter to keep behaving exactly as before:
1select
2 *
3from
4 netsuite.transaction
5where
6 _weld_deleted_at is nullThe deleted rows are where the new answers are. Everything that has disappeared from the source, and when:
1select
2 id
3 , _weld_deleted_at
4from
5 netsuite.transaction
6where
7 _weld_deleted_at is not null
8order by
9 _weld_deleted_at descAnd because the row keeps every value it had, a report run over a past period can include the records that existed at the time, rather than silently restating history every time something is deleted upstream.
Where it works today
Capture deletes needs a full sync that reads a complete snapshot of the source, and a table with primary keys. That's true of a minority of tables, so we're adding support connector by connector:
| Connector | Tables |
|---|---|
| Google Ads | The dimension reports, such as campaign, ad_group and ad, with their bidding strategy and criterion subtables |
| Microsoft Ads | account, ad, ad_group, budget, campaign, keyword and label |
| NetSuite | The SuiteQL tables, including transaction, transactionline, transactionaccountingline, entity and item |
| Microsoft SQL Server | Every table with primary keys, including SQL Server on RDS and Azure SQL Database |
| Traede | category, customer, product, variant, order, invoice, production_order and production_order_delivery_note |
The easiest way to check a table is the option itself: it only appears on tables that support it.
Your data warehouse has to be able to merge a snapshot into an existing table, so Capture deletes works on BigQuery, Snowflake, Redshift, Postgres, Microsoft SQL Server, MotherDuck and Apache Iceberg.
How it compares to history tables and CDC
Weld has two other ways of keeping track of change, and they answer different questions:
- History tables keep every previous version of a row, so you can see what a record looked like before it was edited. Capture deletes keeps the records that were removed altogether.
- Change Data Capture reads a database's change log, so it sees deletes as they happen. Capture deletes works from full syncs instead, which is what makes it possible for sources that have no change log at all, like an ad platform or an ERP's API.
How to turn it on
Open the table's settings (the cogwheel) in your data source configuration and toggle Capture deletes, just above the History tables option. The table then shows a Captures deletes label next to its sync mode.
If the table syncs incrementally, it also needs a full sync schedule, for example every Sunday. Deletes are only reconciled on a full sync, so the schedule decides how quickly a deletion shows up.
Building syncs over the Weld Connect API or the MCP server? The setting is soft_delete_enabled on a table. You can check support before turning it on: soft_delete_supported on each table from get_elt_sync_available_streams, and your warehouse's support from GET /data_warehouse or the MCP get_account tool.
What to know before you start
- It's in beta, and off by default. Nothing changes on a table until you turn it on for that table.
- Deleted rows stay in the table, so a table with Capture deletes grows rather than shrinks as records disappear at the source.
- Some schema changes need a rebuild. If the source changes shape in a way the warehouse can't apply in place, the table is locked, you're notified, and the change is applied on the next full sync you request. A rebuild clears the deletion markers.
- You can clear the markers on purpose by requesting a full sync and choosing to clear captured deletes, or with
clear_soft_deleted_rowsover the API.
Read the full guide in the Capture deletes documentation.
FAQ
What does Capture deletes do?
It keeps rows that a source stops returning, instead of letting a full sync remove them from your warehouse. Each kept row is marked with a _weld_deleted_at timestamp recording when the record disappeared, so you can still query it.
Which plans include Capture deletes?
Capture deletes is available on the Premium and Business plans.
Which connectors support Capture deletes?
Google Ads, Microsoft Ads, NetSuite, Microsoft SQL Server (including SQL Server on RDS and Azure SQL Database) and Traede, on the tables listed above. More connectors are being added table by table.
How do I exclude deleted rows from my models?
Filter on _weld_deleted_at is null. Rows that are still live at the source always have a null in that column.
Is Capture deletes the same as change data capture?
No. Change data capture reads a database's change log and sees deletes as they happen. Capture deletes compares full syncs, so it works for API sources that have no change log.



