What a click webhook actually is
When someone clicks your short link or scans your QR code, the platform POSTs a JSON event to an endpoint you control — within seconds, not in next week's CSV export. That single mechanism is what turns a link from a passive redirect into a trigger: open a ticket when an asset tag is scanned, ping sales when a proposal link is opened, kick off a Zapier or n8n workflow, update your CRM.
A typical event looks like this:
{
"event": "click",
"source": "qr",
"code": "spring24",
"shortUrl": "go.acme.com/spring24",
"destination": "https://acme.com/offer",
"tags": { "campaign": "spring", "site": "leeds" },
"at": "2026-07-12T11:20:00+00:00",
"ua": "Mozilla/5.0 (iPhone..."
} Who offers click/scan webhooks (July 2026)
Support differs more than any other feature in this category. Every fact below links to the vendor's own pricing page or documentation:
| Platform | Click/scan webhooks | Cheapest plan with them | Delivery guarantees |
|---|---|---|---|
| Bitly | Yes — single combined “engagement” event [source] | Enterprise (sales-led) [source] | Retries documented; Enterprise-gated |
| Dub | Yes — typed events incl. link.clicked [source] | Business, $90/mo [source] | Signed + retried — genuinely strong |
| Short.io | Yes — click events, one webhook URL per domain [source] | Pro, ~$18/mo [source] | Signing/retries not documented |
| Rebrandly | Yes — “Clickstream” click + scan events [source] | Professional, $32/mo [source] | Delivered in JSON batches (or to S3) [source] |
| TinyURL | No webhooks at any price (API is pull-only) [source] | — | — |
| xengo | Yes — per-event click/scan delivery (details) | Pro, £39/mo (pricing) | HMAC-signed, retried ~45 min with backoff, per-attempt delivery log |
Deeper side-by-sides live on our comparison pages — each with the same cite-everything rule as this table.
The three things that separate serious webhooks from a checkbox
1. Signatures
Anyone who discovers your endpoint URL can POST fake events to it — unless
deliveries are signed. The de-facto standard is the Svix scheme: a
webhook-id, a webhook-timestamp and a
webhook-signature header carrying an HMAC-SHA256 over
id.timestamp.body, keyed with a secret only you hold.
Verification is a few lines of stdlib:
import base64, hashlib, hmac
def verify(secret, headers, raw_body: bytes) -> bool:
key = base64.b64decode(secret.split("_", 1)[1])
signed = (f"{headers['webhook-id']}."
f"{headers['webhook-timestamp']}.").encode() + raw_body
want = base64.b64encode(
hmac.new(key, signed, hashlib.sha256).digest()).decode()
return any(hmac.compare_digest(f"v1,{want}", c)
for c in headers["webhook-signature"].split()) 2. Retries with a stable event id
Your endpoint will be down sometimes. A serious platform retries
with increasing backoff and keeps the event id identical across attempts,
so de-duplicating on webhook-id makes at-least-once delivery
effectively exactly-once for your logic. If retry behaviour isn't in the
docs, assume fire-and-forget.
3. A delivery log
When someone asks “did the alert go out?”, you want a per-attempt record — timestamp, attempt number, HTTP result — not a shrug. Few platforms offer one; it's worth checking before you build a workflow that matters on top.
Webhooks vs Zapier triggers
Automation platforms blur the picture: a “Zapier integration” may be a real-time webhook-backed trigger or a poller that checks every 15 minutes (and burns a Zapier task per click). If latency matters, look for the word instant on the trigger, or paste a catch-hook URL into a platform that POSTs per event. The same test applies to Make and n8n.
Try it in two minutes
On xengo: create a Webhook channel in the console (you'll get a
whsec_ signing secret, shown once), select the channel on a
link, then click the link — the signed event arrives with the headers
above, and every attempt shows in the channel's delivery log.
The full delivery-guarantees story is here.