A practical field guide from Automation Ace.
Avoiding Zapier Webhook Deduplication with Unique Timestamp Values
Zapier's webhook trigger uses deduplication to avoid processing the same event twice. It compares each incoming request to recent previous requests using a deduplication key derived from the payload. When two requests have identical payloads — same body, same fields, same values — Zapier treats the second as a duplicate and skips it. This is useful when external systems accidentally retry, but it breaks intentional repeated sends: self-triggering webhook loops, scheduled pings, or workflows where the same status value legitimately recurs.
How Zapier Deduplicates Webhook Triggers
When a Zapier Catch Hook trigger receives a request, Zapier hashes a portion of the request payload to generate a deduplication ID. If that ID matches a recent run, the trigger fires but Zapier marks the item as already seen and the Zap does not run its downstream steps. The deduplication window is typically the most recent 10–100 entries (Zapier does not publish the exact window size).
The practical consequence: if you send a Webhooks by Zapier POST action to a Catch Hook trigger in a self-triggering loop, and the payload is the same every iteration, the loop stops after the first run because every subsequent webhook looks identical to the last.
The Fix: Add a Unique Value to Every Request
The solution is to include a field in the webhook payload that changes on every send — a timestamp, an incrementing counter, or a random value. Zapier hashes the full payload, so changing any single field makes the request unique.
Three approaches, from simplest to most robust:
Option 1: Timestamp in the Webhook Payload (No Code Step Needed)
In the Zapier Webhooks action (POST or PUT), add a field to the Data payload using Zapier's built-in Current Time value from the trigger or a formatter step:
- Add a field named
_ts(or any name) to the Data section of the Webhooks action - Set its value to the Current Time dynamic field available in any Zap
This works when the Zap already has a timestamp from the trigger or a Date/Time formatter step. The _ts field changes each run, making each payload unique. The receiving Catch Hook gets an extra field — ignore it or strip it in a downstream Code step.
Option 2: Generate a Timestamp in a Code Step
When no existing timestamp is available, use a JavaScript Code step before the Webhooks action to produce one:
// Run this Code step before your Webhooks action
// Output the timestamp as an input field in the Webhooks payload
const ts = Date.now(); // milliseconds since epoch — unique on every run
const tsIso = new Date(ts).toISOString(); // "2024-03-15T14:23:07.542Z"
output = {
timestamp_ms: String(ts),
timestamp_iso: tsIso
};
Then in the Webhooks action, add _ts → {{timestamp_ms}} (or timestamp_iso) to the Data section. Every request will have a different millisecond timestamp, making each payload unique.
Option 3: Generate a Random Nonce (UUID-Style)
A timestamp can theoretically collide if two runs happen in the same millisecond (unlikely but possible in high-frequency loops). A random nonce guarantees uniqueness:
// Generate a random ID for this specific request
const nonce = Math.random().toString(36).slice(2) + Date.now().toString(36);
// e.g. "k7f2x9p1abc4d5e6"
output = {
nonce,
timestamp_ms: String(Date.now())
};
For a more standard format, Zapier's JavaScript environment includes the crypto module:
const crypto = require('crypto');
const nonce = crypto.randomUUID(); // "550e8400-e29b-41d4-a716-446655440000"
output = { nonce };
Pass {{nonce}} as a field in the webhook payload. The receiving Zap can discard it — its only purpose is to make each payload hash differently.
Option 4: Include the Nonce in the URL Query String
Instead of adding a field to the body, append the timestamp to the webhook URL as a query parameter. Zapier includes the URL in the deduplication hash for GET requests (and some POST configurations):
// Build the webhook URL with a cache-busting timestamp
const baseUrl = inputData.webhook_url; // e.g. "https://hooks.zapier.com/hooks/catch/123456/abcdef/"
const ts = Date.now();
const url = `${baseUrl}?_ts=${ts}`;
output = { url };
Use {{url}} as the URL in the Webhooks action instead of the static base URL. Each request goes to a slightly different URL, which Zapier treats as distinct.
Receiving End: Ignoring the Deduplication Field
The receiving Catch Hook Zap gets an extra _ts or nonce field in its trigger data. If the downstream steps don't need it, no action is required — just don't map it to anything. If you want to strip it explicitly before passing data onward:
// In a Code step on the receiving Zap
const { _ts, nonce, ...data } = inputData;
// data now contains all fields except _ts and nonce
output = data;
Self-Triggering Loop Pattern
The most common scenario for this fix is a self-triggering sequential queue or processing loop, where Zap A sends a webhook to its own Catch Hook to re-trigger itself. Here's the complete pattern:
// Code step: build the next-iteration payload with a unique timestamp
const payload = {
record_id: inputData.record_id,
iteration: String(parseInt(inputData.iteration || '0', 10) + 1),
_ts: String(Date.now()) // prevents deduplication
};
output = {
payload_json: JSON.stringify(payload),
iteration: payload.iteration
};
Then in the Webhooks POST action:
- URL: your Catch Hook URL
- Payload Type: Json
- Data:
{{payload_json}}as the raw body (or map individual fields including_ts)
Deduplication vs. Rate Limiting
Deduplication and rate limiting are separate issues. Deduplication silently skips identical events — the Zap history shows the trigger firing but the run stopping immediately. Rate limiting throttles how often a Zap can run regardless of uniqueness. If your Zap is being skipped and the payloads are already unique, check the Zap history for rate limit errors rather than deduplication. For custom schedule intervals and loop patterns, both can apply.
Zapier deduplication is a protection mechanism, not a bug — it prevents external systems from accidentally re-processing events. The fix for intentional repeated sends is simply to make each request provably unique by including a field that changes every time:Date.now()as a millisecond timestamp is the simplest,crypto.randomUUID()is the most collision-proof. Add it to the payload, pass it through, and discard it on the receiving end if it's not needed.
For the self-triggering sequential queue pattern this commonly appears in, see sequential queue with Webhooks and Zapier Tables. For sending webhook requests with custom fields and headers, see passing data through Webhooks in Zapier. For round robin and stateful patterns that send repeated requests, see round robin and array randomization in Zapier. For help designing a loop or queue workflow, talk to Automation Ace.
Disclaimer: This article may include links to apps, products, or services. Some links may be affiliate links, which means Automation Ace may earn a commission at no extra cost to you.