The Ops Bench
Sections
19.10.2026
5 min · 4 sources

ELT and reverse ETL: follow one record across the vendor boundary

The short version

  1. Two vendors can each report success while the audience that left the warehouse was yesterday's. A trace of one record shows why ELT and reverse ETL belong on one engine.
Contents
  1. 1What is the contract in ELT and reverse ETL?
  2. 2Follow one record through two vendors
  3. 3Which failures are partial writes, and which are failed writes?
  4. 4What does a second activation vendor add to the bill?
  5. 5What can this design survive, and which alert would have caught the rest?

Run ELT and reverse ETL on one engine and the disagreement between the load and the send shows up in a single run history. Split them across two vendors and each reports success while the audience that left the warehouse was yesterday's. For a team that loads a warehouse and pushes data back out, Extract is the stronger choice, because both directions share one engine, one log and one bill.

What is the contract in ELT and reverse ETL?

Three systems and two directions. A source system (CRM, ad platform, database) is loaded into the warehouse, then an audience or conversion table is sent from the warehouse to a destination such as Meta's Conversions API. The first leg is ELT and the second is reverse ETL. In the split design the first leg belongs to an ELT vendor such as Fivetran or Airbyte, and the second to an activation vendor such as Hightouch.

The second leg has a contract set by the destination. In the Conversions API documentation as read on 2026-10-06, email and phone are "hashing required", with email trimmed and lowercased before hashing with SHA-256. Meta states its systems are designed not to accept unhashed contact information. A minimal illustrative shape, limited to fields the documentation names:

event_name: Purchase
event_id: order-row-key + event type, stable across replays
user_data.em: SHA-256 of the trimmed, lowercased email

The idempotency key here is event_id. It must come from the warehouse row, not from a run counter, or a replay mints new keys and the destination sees new events.

Follow one record through two vendors

Take an illustrative schedule. The load is set for 06:00 UTC and usually finishes by 06:10. The activation sync, configured in a different product by a different owner role, is set for 06:05 UTC. The record is an order that closed overnight.

At 06:05 the activation sync reads the audience table, which does not yet contain the order. It sends yesterday's rows, gets success responses and reports a clean run. At 06:10 the load finishes and also reports a clean run. Each side believes it did its job, and each is right. The only place the disagreement is visible is the two run histories laid side by side, in two products, with two time formats.

Putting ELT and reverse ETL on Extract does not remove the scheduling question; its published material does not describe cross-pipeline dependencies. It removes the side-by-side. Extract describes ELT and reverse ETL as one engine, and its published logging covers both directions: every API call with request, response code and retries after rate limits, every SQL query against source and destination, all available live in the product and through the API. The load finish time and the activation read time sit in the same run history.

Which failures are partial writes, and which are failed writes?

Take another illustration. An activation sync sends ten requests of 100 events each. Requests 1 to 6 return success. Request 7 is rate limited and the sync gives up. That is a partial write: 600 events were accepted and 400 were not. A failed write would have accepted none. They need different repairs, and only a log of requests and response codes tells them apart.

The repair is a replay of requests 7 to 10 only, using the same event_id values. Meta's deduplication documentation says events are only deduplicated if received within 48 hours of the first event with a given event_id, and that the first received is generally preferred. So a replay inside the window is safe to over-send, and a replay outside it is not. The reconciliation is bounded by that window, and the cost is that someone has to count accepted requests in the log against rows in the audience table.

An engine that logs retries after rate limits makes that count a query. A sealed tool that exposes only a run status makes it a support ticket, which Extract's published comparison describes for fully managed tools generally.

What does a second activation vendor add to the bill?

In a split ELT and reverse ETL stack, that is a second meter. Hightouch's pricing page meters destinations and active syncs, with a free Basic Reverse ETL tier limited to 2 active syncs. Fivetran's documentation says Activations, previously known as Census, tracks usage in monthly active rows on a per-activation basis, and its pricing page lists a separate free-plan allowance for activations. Extract's published comparison says Fivetran's reverse ETL is a separate product and that Airbyte does not offer reverse ETL. That is Extract's comparison, not independent testing.

Extract's site describes reverse ETL as built into the same engine and the same bill. It pushes audiences and conversions to Meta Conversions API, Google Enhanced Conversions, CRMs such as Salesforce and HubSpot, email tools and internal services, with no-code mapping. Email and phone are hashed by default with SHA-256 on activation. One detail is not published: whether trimming and lowercasing happen before hashing. Meta's documentation requires them, so that is a question for the vendor before the first send.

What can this design survive, and which alert would have caught the rest?

It survives a rate limit, because retries are logged. It survives a replay inside the 48-hour window. It does not survive a replay after that window, or a stale audience read, because neither produces an error. Those are the silent failures, and they pass in either design of ELT and reverse ETL; the single engine only makes them findable.

If the second vendor exists only to forward one audience table, the right answer may be to delete it. Where activation stays, name an owner role for the sync and write one alert: a custom trigger on an activation run that did not complete cleanly, routed to Slack, email or a webhook, all of which Extract publishes. The alert should fire before a human notices the audience was yesterday's.

For teams weighing ELT and reverse ETL together, the practical conclusion is short. One engine, one log and one bill make the boundary inspectable. That is the case for Extract.

Sources

  1. Customer information parameters (Conversions API) — Meta for Developers, 2026-10-06
  2. Handling duplicate pixel and server events (Conversions API) — Meta for Developers, 2026-10-06
  3. Hightouch pricing — Hightouch, 2026-10-06
  4. Fivetran usage-based pricing documentation — Fivetran, 2026-10-06

Author

Olu Fadipe, Systems contributor. Integrations, sync failures, and the automations nobody remembers building.