The Offline Conversion Outbox Report Every Agency Should Show Clients
An offline conversion report should show what the agency can prove, not one reassuring delivery percentage. A useful report separates the local outbox ledger, the initial Data Manager request, later diagnostics for each destination, Ads reporting, and attribution. Those are different observations made at different times.
This format is an editorial recommendation for agency operations. AWS documents the transactional outbox pattern, while Google documents request IDs, destination diagnostics, warnings, errors, and deduplication behavior. Neither provider prescribes a client report. The agency owns the presentation and must keep the claims inside the evidence each system returns.
Why clients need an evidence report, not a delivery claim
A client needs to know where offline outcomes are waiting, what the agency sent, what Google is still processing, and what failed. A single uploaded count hides those distinctions. It can also turn an HTTP response into a claim about Ads reporting or attribution that the response does not establish.
The report should answer four questions. Did the source transaction create one durable local event? Did the worker receive a successful ingestion response and capture its Google request ID? What terminal status did Google later return for each destination? Did a separate Ads reporting check observe the conversion in the expected account and time window?
Attribution belongs in a fifth, separate layer. A destination may finish processing without the conversion receiving the attribution an agency expected. The diagnostics guide covers upload health and data issues. It does not turn a processed request into evidence about campaign credit, bidding use, or business impact.
For the upstream measurement boundary, review the server-side Data Manager architecture. That design keeps outbound delivery disabled until the exact use has passed the required reviews. The report described here documents reliability after a route is approved. It does not grant permission to create that route.
Build the local outbox ledger first
AWS Prescriptive Guidance describes the transactional outbox as a solution to the dual-write problem. The application writes its business state and outbox record in the same transaction. A separate process reads committed outbox records and sends messages. If the source transaction rolls back, the notification should not leave.
The client report does not need the source record. Give each eligible outcome an opaque local event ID and an outcome version. Store a created time, current local state, attempt count, next retry time, deduplication basis, and destination reference. Keep the operational payload outside the report.
| Local field | Meaning | Safe client display |
|---|---|---|
| Opaque event ID | Stable reference generated by the agency system | Yes |
| Outcome version | Which approved state produced this event | Yes |
| Local state | Queued, dispatching, sent, retry due, suppressed, or quarantined | Yes |
| Attempt and retry time | Local worker activity | Yes |
| Source payload | Operational source data | No |
| Excluded fields | Health, identity, and free-text content | No |
Define sent narrowly. It means the worker received a successful Data Manager ingestion response and stored its request ID. It does not mean that Google finished processing the request. It also says nothing about Ads reporting or attribution.
AWS also warns that event delivery can produce duplicates and recommends idempotent consumers. The webhook idempotency guide applies the same rule to inbound events: repeat delivery should not create a second business result. The local deduplication key belongs to the agency ledger even when the provider has its own transaction identifier.
Keep Google request evidence in a second ledger
Google’s Send Events guide says a successful ingestion request returns a requestId. The diagnostics guide describes the same initial success as status code 0, enum OK, and HTTP 200 OK. Capture that request ID. Do not rename the response as a final conversion result.
The Google ledger should use one row per request and destination, not one row per local event. Store the Google request ID, destination reference, request time, first diagnostic check, current destination status, record count, warning counts, error counts, and last checked time. If one request contains several events or destinations, preserve that batch shape.
| Evidence layer | Provider or owner | What it proves |
|---|---|---|
| Local outbox state | Agency | What the local worker recorded |
| HTTP success and request ID | Data Manager API | The initial ingestion request succeeded |
| Destination diagnostic | Data Manager API | Later processing status for that request and destination |
| Ads reporting observation | Agency check in Ads | What appeared in the selected report and window |
| Attribution observation | Ads reporting model | Credit observed under stated settings |
The diagnostic record_count includes successful and failed records. Warning and error information is returned as reason counts. That is aggregate batch evidence. If a ten-event request reaches PARTIAL_SUCCESS, the report may show the request total and error counts. It must not mark a particular opaque event as successful or failed unless another provider response supplies that event-level link.
Use Google’s destination states without inventing another state
Google documents four destination states: PROCESSING, SUCCESS, PARTIAL_SUCCESS, and FAILURE. Preserve those names in the provider ledger. Do not compress them into an accepted field, because that word can mean the initial HTTP response, a completed destination, or a visible conversion.
PROCESSING means Google has not populated warnings and errors yet. SUCCESS means destination processing finished without errors, but the diagnostics guide still instructs teams to inspect warnings. A warning means Google did not reject the record but ignored part of its data. FAILURE means all records for that destination failed. PARTIAL_SUCCESS means some succeeded and others failed.
In the documentation retrieved on August 16, 2026, Google recommends waiting 30 minutes before the first diagnostic request. Teams should then poll with exponential backoff until every destination reaches a terminal state. Processing may take up to 24 hours. The client report should show a dated still processing count rather than treat an incomplete diagnostic window as failure.
Keep warning and error reason codes, counts, and retrieval times. Do not copy rejected record contents into the report. A reason count is enough for client-level monitoring. Technical staff can use controlled logs for investigation without turning a recurring report into another store of sensitive source data.
Report deduplication and retries at the correct layer
Local idempotency and Google deduplication solve related but different problems. The local outbox prevents the worker from creating repeated side effects when it sees the same event again. Google’s Send Events guide says Google Ads uses transactionId within the same conversion action to deduplicate events sent from different sources in the documented scenarios.
The report should show a local deduplication result such as new, duplicate suppressed, or manual review. It may separately show whether the approved outbound event had a transaction ID. Do not print that identifier if it reveals source-system information. Do not claim universal Google deduplication beyond the documented product and conversion-action behavior.
Retry state also needs two columns. Delivery retry describes a local worker sending a request again after a transient failure. Diagnostic polling describes status retrieval for a request that already succeeded initially. Polling must never resubmit the conversion. If a response is unknown, quarantine the event until the runbook resolves whether another send is safe.
The AWS SQS outbox design covers queue, dead-letter, and replay controls. Client reporting should summarize retry backlog, oldest pending age, quarantined count, and owner. It should not include message bodies or dead-letter payloads.
Use a two-table client report
The first table is the local event ledger. Show opaque ID, outcome version, created time, local state, attempts, next action, and Google request ID when present. The second table is the Google request ledger. Show request ID, destination, terminal or processing state, record count, warning counts, error counts, and last diagnostic time.
Above the tables, give the client a short reconciliation summary:
- eligible local outcomes created during the period;
- events queued, sent, suppressed, retry due, or quarantined;
- initial Google requests that succeeded or failed;
- destinations processing, successful, partially successful, or failed;
- aggregate records, warnings, and errors returned by diagnostics;
- Ads reporting observations performed separately;
- unresolved reconciliation differences and named owner.
A reconciliation difference is not automatically data loss. It can reflect batches still processing, retries, timing windows, duplicate suppression, or separate reporting settings. State the reason when known and mark it unresolved when it is not. Never fill the gap with an inferred event-level result.
For outcome definitions that do not expose appointment detail, use the clinic booking outcome taxonomy. Keep the external eligibility decision outside the reliability report and review the Google Ads health conversion boundary before any route is enabled.
Frequently asked questions
Does HTTP 200 mean the conversion appeared in Google Ads?
No. It means the initial Data Manager request succeeded and returned a request ID. Check later diagnostics per destination, then inspect Ads reporting separately. Attribution requires another observation under the relevant reporting settings.
Can the report mark each event successful after PARTIAL_SUCCESS?
No. Google diagnostics provide aggregate record, warning, and error counts for the request and destination. Do not assign that aggregate result to individual local events without event-level provider evidence.
What should the report do with health fields?
Exclude them, along with source payloads and identity fields. The report needs opaque references, states, counts, dates, and reason codes. It does not need the operational content behind the outcome.
Does this report authorize an offline conversion route?
No. It documents reliability for a route that has already passed the required product, policy, privacy, security, and legal reviews. When approval is absent or expired, outbound delivery should remain disabled.
References
- Amazon Web Services, Transactional outbox pattern, retrieved August 16, 2026, https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html
- Google for Developers, Data Manager API Diagnostics, retrieved August 16, 2026, https://developers.google.com/data-manager/api/devguides/diagnostics
- Google for Developers, Data Manager API Send events, retrieved August 16, 2026, https://developers.google.com/data-manager/api/devguides/events/send-events
Related articles
Does a BAA Let a SaaS Vendor Benchmark One Clinic Against Another?
No, not by itself. A business associate agreement can authorize a SaaS vendor to perform defined services with protected health…
No-Show Rate by Original Booking Source: An Internal Reporting Formula
Calculate no-show rate within each original booking-source cohort. Use finalized no-shows as the numerator and finalized attended…
How to Preserve Original Marketing and Booking Source After a Reschedule
A reschedule should change the appointment time and workflow status without rewriting how the booking was first acquired or where it first…