Deduplication
The pattern: fire the same event from the pixel AND from your server.
Skryx dedupes by event_id. Each event is counted once. You get
"server-side accuracy + browser-side reach" without doubling counts.
This is Meta's Conversions API + Pixel pattern. Same logic, here.
# The dedup key: event_id
Every event carries an event_id chosen by the sender. Within a
single tenant, the same event_id is processed at most once
regardless of:
- Which channel sent it first (pixel vs server)
- How many times it was retried (network failure, queue replay)
- Which day it falls under (dedup windows are 48h)
# Why dedup matters
Take order.completed:
- The pixel fires it on the thank-you page — fastest, but lossy (user closes the tab before the page loads, ad-blocker, browser back button, etc.).
- Your server fires it from the order webhook — slower (real-time attribution lags by seconds), but never lost.
If you fire both, you'd double-count every order without dedup. With dedup, accuracy = server-side, reach = pixel-side.
# Implementing the pixel + server combo
The recipe is "same event_id from both sides":
event_id = "ord_" + order.id // stable, deterministic
# Pixel side
// On the thank-you page
skryx.track('order.completed', {
order_id: '42',
total: 199.99,
// your pixel-side fields here
});
By default the pixel auto-generates event_id = "evt_…". For
combo dedup, override it in properties.event_id_override, or
issue the event manually with a known event_id. The simplest
combined pattern:
<!-- On thank-you page server-rendered HTML -->
<script>
skryx.track('order.completed', {
event_id: 'ord_42', // shared with server-side call
order_id: '42',
total: 199.99
});
</script>
# Server side
POST https://api.skryx.io/v1/events
{
"events": [{
"event_id": "ord_42", ← SAME id
"event_name": "order.completed",
"source": "server",
"occurred_at": "...",
"session_id": "...",
"properties": { "order_id": "42", "total": 199.99, ... }
}]
}
First side wins. The other side sees:
204 No Content(pixel) oraccepted: 0, rejected: 0(server)- A bump on the
deduped_24hcounter in the dashboard
# What "dedup" actually does
- Pixel + server both POST. Whichever arrives first → processed.
- The second arrival's
event_idis recognised and the event is dropped instead of being counted again. - The drop is reflected in the dashboard's "Dedup rate" card so you can verify the combo is working.
# Operational details
- Dedup window: 48 hours. Plenty for pixel + server retries.
- Server-side guarantee: dedup is enforced at multiple layers, so even under failure conditions duplicates do not slip through.
- No retries needed on your end: if you POST the same batch twice in a row (network jitter), the second pass is a no-op.
# Verifying it works
After a few real events, check /tracking:
- Dedup rate card shows percentage of duplicates dropped.
- Live feed shows each unique event once — duplicates never appear here.
- By source counters split into
pixelandservercolumns. For order events with the combo, you'll typically see pixel ≈ 70%- server = 100% (because dropping the pixel-version when the server arrived first counts toward the server, not the pixel).
# Anti-patterns
- Don't randomize event_id between pixel and server — defeats dedup.
- Don't use the same event_id for different events — only matches when both event_name + event_id match. Different event types share the same dedup namespace.
- Don't retry forever on 429: respect
quota_exceeded, back off until tomorrow.