A browser purchase event and a server purchase event can each pass their own payload checks while describing the same order with different identifiers. The receiving platform then lacks the shared identity your integration intended to provide.
Meta's event model uses event ID and event name when deduplicating browser and server submissions. The application work begins earlier: establish one identity for the business event and preserve it through both delivery paths.
This walkthrough tests that propagation locally. It does not send Pixel or Conversions API requests, and its browser objects are application fixtures rather than Pixel API calls.
Create the identity when the business event becomes durable
Suppose checkout commits order order-1042. At the same durable boundary, store the identity for the purchase event that should represent that order in the intended destination.
The browser response and server delivery worker should read that stored identity. Generating a random value independently inside each adapter defeats the relationship before either request leaves your application.
A network transmission attempt needs its own operational identity. Keep that separate from the business-event ID. Retrying an event after a timeout is another attempt to deliver the same event, not necessarily another purchase.
If the browser never receives the checkout response, the server may still deliver its event. Your design should not require both paths to succeed before the order itself is considered committed.
Test both adapters against the same record
Save this complete example as a Node.js module and run it locally:
import assert from 'node:assert/strict';
function eventRecord(id, destination) {
if (typeof id !== 'string' || id.trim().length === 0) {
throw new TypeError('stable business-event ID required');
}
return { id, name: 'Purchase', destination };
}
function browserAdapter(event) {
return { name: event.name, eventID: event.id,
destination: event.destination };
}
function serverAdapter(event) {
return { event_name: event.name, event_id: event.id,
destination: event.destination };
}
function sameIdentity(browser, server) {
return browser.name === server.event_name &&
browser.eventID === server.event_id &&
browser.destination === server.destination;
}
const stored = eventRecord('purchase-event-1042', 'synthetic-dataset-a');
const browser = browserAdapter(stored);
const server = serverAdapter(stored);
const retry = JSON.parse(JSON.stringify(server));
assert.equal(sameIdentity(browser, server), true);
assert.equal(sameIdentity(browser, retry), true);
assert.equal(sameIdentity(browser, { ...server, event_id: 'retry-random-id' }), false);
assert.equal(sameIdentity(browser, { ...server, event_name: 'purchase' }), false);
assert.equal(sameIdentity(browser, { ...server, destination: 'dataset-b' }), false);
assert.notEqual(serverAdapter(eventRecord('purchase-event-1043',
stored.destination)).event_id, server.event_id);
assert.throws(() => eventRecord('', stored.destination));
The destination field is local test metadata. It is not an additional CAPI event field. It ensures the fixture does not report a successful pairing when the two submissions are configured for unrelated destinations.
The example checks identity only. A complete server payload requires the rest of the destination contract, including appropriate event context and user data handled under the application's actual permissions and requirements.
Keep retries tied to the original event
Persist the event payload or enough immutable data to rebuild it consistently. A worker retry should not create a new event ID simply because it reconstructs the JSON.
Record an attempt number, send time, response metadata and error classification outside the business-event identity. Those fields let operators investigate delivery without changing what the event represents.
Consider the ambiguous-response case. The server may have accepted a request before your client timed out. Your local state should preserve that uncertainty and retry according to the documented destination contract. An HTTP timeout does not prove that the destination never received the first attempt.
Do not claim exactly-once reporting merely because you have a stable identifier. Stability is one input to the destination's deduplication behavior. Other conditions and delivery timing still apply.
Guard against the opposite identity bug
One constant event ID reused for every purchase is just as problematic as a new ID on every retry. Distinct business events need distinct identities within the intended scope.
Add a fixture for two different committed orders and assert that their event IDs differ. Add another fixture for a repeated delivery attempt and assert that its ID remains unchanged.
Also test browser refreshes or repeated confirmation-page renders. Decide whether they are re-presenting the same purchase event or representing a genuinely different operation. Generate identifiers from that business decision, not from page lifecycle events alone.
Avoid embedding personal information in IDs. Use an opaque identifier suitable for operational correlation. Keep any internal mapping to customer records in the application storage that already governs access to those records.
Check the actual outgoing requests
Unit tests on adapter objects can miss later tag-manager transformations or HTTP middleware. Capture the browser event arguments and serialized server body in a controlled integration test.
Compare exact event names and IDs, including case and whitespace. A value copied through a template can acquire a different representation even when the initial application record was correct.
Preserve the intended destination configuration with the captured pair. Two matching IDs in logs do not establish that the requests reached the same place.
If the browser and server are maintained by different teams, share a small identity contract and the same synthetic fixture. That gives both implementations a common expected result without requiring them to share all payload construction code.
Verify the outcome in destination diagnostics
Use a controlled event pair and inspect the destination's available event diagnostics. Retain the local record, request metadata and observed pairing outcome. Do not infer successful deduplication from a local equality assertion or a successful HTTP response.
If the result differs, investigate arrival, destination configuration, exact identity values and the currently documented matching conditions. Avoid changing several of those at once, since the next test would not identify which change mattered.
I maintain Pixellint. Its Meta Conversions API pack helps inspect the server payload. Keep the shared-identity tests beside the browser and server adapters because the relationship spans both paths and cannot be established from either payload alone.
Sources
Technical sources checked October 25, 2026. Drafted with AI; examples are synthetic unless explicitly stated otherwise.
Top comments (0)