Integrations · webhooks in and out
Analytics webhooks: signed leads in, conversions and alerts out
Analytics webhooks in Skald work both ways. Calendly, Cal.com, HubSpot, Typeform, Stripe, Zapier, Make and your own server send each lead signed; Skald sends conversions and alerts to your CRM, Zapier or Slack, never with a name or an email.
Analytics webhooks are messages one tool posts to another's address the moment something happens: a booking, a payment, a form, an alert. Each Skald hook has its own address and secret, checks the signature before it keeps anything, and keeps each conversion once. One of the Skald integrations.
30-day free trial · no card · we set it up within one working day · free to self-host
- 09:02 stripe · checkout.session.completedkept
- 09:02 stripe · the same event againalready had it
- 10:15 json · from Zapier, Bearer keykept
- 11:31 lead · time 9 minutes offbad signature
- 11:44 typeform · Send a test eventtest, read and not kept
Sample deliveries. Each message a hook received, with its outcome in words.
[01] webhooks in
Incoming webhooks for bookings, forms and payments
Each tool gets its own address and its own secret on Settings › Integrations. Pick a tool: who makes the secret, which events to send, and what Skald counts. Every lead lands in lead attribution.
pick a tool
Calendly: either side makes the secret
Send invitee.created, invitee.canceled and invitee_no_show.created. A booking counts as Demos, completed; a cancellation as cancelled or rescheduled; a no-show as no-show. Calendly sends webhooks on its paid plans, made through its API.
Cal.com: either side makes the secret
In Cal.com, Settings › Developer › Webhooks: Booking Created, Booking Cancelled, Booking Rescheduled. Pass the visitor ID in the embed as metadata[skv], or as a hidden booking question named skv, to join the booking to the journey.
HubSpot: your app's client secret
contact.creation counts as a Contact form, a meeting's object.creation as a Demo, and a deal moved to closed won as a won Deal. A workflow's Send a webhook action works too, signed by the same app.
Typeform: either side makes the secret
Connect › Webhooks › Add a webhook. Each response counts as a Contact form, completed. A hidden field skv joins it to the journey. Skald never reads the answers.
Stripe: Stripe makes the secret (whsec_)
Send checkout.session.completed and checkout.session.async_payment_succeeded. A paid Checkout counts as a Payment; a delayed method counts as started first, then paid. Skald never reads customer details.
Zapier, Make, n8n: Skald makes the secret
A POST with a JSON body and the header Authorization: Bearer <your-secret>, no signing code. Two fields are needed, external_ref and action. One message can carry up to 100 records.
Your own server: Skald makes the secret
Sign each lead with the secret, or download one file for PHP, Node or Python and call one function after the form is saved. WordPress needs no code: one plugin sends Contact Form 7, WPForms, Gravity Forms, Elementor Pro and Ninja Forms leads.
[02] signed, or refused
Webhook signature verification, before anything is kept
A hook does nothing until it has a secret: its address answers "not found". Once it has one, every message is checked against it before it is read.
- Your server signs with
X-Skald-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>of the time, a dot and the raw body. - A time more than 5 minutes off Skald's clock is refused.
- No-code tools may send the secret as a plain key instead, on the json and lead hooks only, and only without a signature header.
- Leaked? Rotate secret: the old one stops at once.
Make can sign too; the formula is in the webhooks help page.
$ BODY='{"external_ref":"L-1001","action":"demo"}' $ T=$(date +%s) $ SIG=$(printf '%s.%s' "$T" "$BODY" \ | openssl dgst -sha256 -hmac "<your-secret>" -hex | sed 's/^.* //') $ curl -X POST 'https://stats.example.com/traffic-hooks/example.com/lead' \ -H 'Content-Type: application/json' \ -H "X-Skald-Signature: t=$T,v1=$SIG" --data-raw "$BODY"
Copy the address from your own Integrations page. Keep the secret out of email, chat and tickets.
[03] retries are harmless
Webhook retries and duplicates, counted once
A tool sends again when it does not get an OK. That is fine: Skald keeps each conversion once per tool, reference and stage, and answers a repeat OK.
Cal.com and Typeform sign no time, so Skald also remembers each of their messages for 30 days and ignores an exact repeat. If Skald cannot save a message, it answers with an error, so the tool sends it again later. One limit is yours to keep: the same lead sent through two tools counts twice. The Status list names it.
- keptrecorded
- already had ita repeat, nothing to do
- not a conversionan event Skald does not count
- bad signaturepaste or rotate the secret
- too largeover 64 KB
- too manyover 60 a minute; the tool retries
[04] webhooks out
Outgoing webhooks to your CRM, Zapier or Slack
Paste an https:// address, tick the events, press Add webhook, and copy the secret shown once. Send a test checks the address answers.
conversion.started,.completed,.cancelled,.rescheduled,.no_show,.abandonedlead.won,lead.lostai.reading_changed: an assistant started or stopped reading a pagealert.opened: any alert, when it opens
Only events after you add the webhook are sent. A failed delivery is tried again for about 15 hours. Remove stops it at once. A Slack address gets Slack's own shape.
{"event": "conversion.completed", "id": "<same on every retry>",
"site": "example.com", "action": "demo", "stage": "completed",
"at": "2026-10-20T14:30:00-04:00", "tool": "calendly",
"external_ref": "<the tool's reference>", "vid": "skv_<id>",
"source_type": "AI assistant", "first_source": "chatgpt.com",
"campaign": null, "landing": "/docs/setup/",
"country": "CA", "device": "Desktop",
"visits_before": 2, "seconds_to_convert": 5400,
"journey": [{"at": "…", "path": "/docs/setup/", "source_type": "AI assistant"},
{"at": "…", "path": "/pricing/", "source_type": "This site"}]}
Sample body. A summary, never a name or an email; the journey is anonymous, at most 50 page views.
[05] what is kept
What Skald keeps from a webhook, and what it drops
Only what attribution needs, and a cut-down copy so every figure can be counted a second time.
- Kept: the action, its stage, the time, the tool, its own reference, the visitor ID when visitor IDs are on, and the source, campaign, landing page, country and device when known.
- Kept for checking: a copy of each verified message, cut down to the fields Skald reads, as long as the leads.
- Always dropped: IP addresses, browser strings, phone numbers, extra emails, form answers, customer details, and Calendly's cancel and reschedule links.
- Names and emails: kept only when the site's setting keeps them.
- The delivery log: when, the outcome and the answer, never the message. Kept 90 days.
[06] what it does not do
What Skald webhooks do not do
Signed, once, and plain about it. Here is what that leaves out.
What it does not do
- The same lead sent by two tools counts twice. Send each lead one way only.
- No journey for a lead whose tool did not carry the visitor ID, or while visitor IDs are off.
- An outgoing message never holds a name or an email. A CRM matches it by the tool's reference it carries.
- Outgoing webhooks send only what happens after you add them: no backfill out.
- The Integrations page needs team accounts. On a one-login server, whoever runs it sets hooks up on the server.
keep reading
More on analytics webhooks
questions
Analytics webhooks FAQ
Straight answers, including what Skald does not do.
Which tools can send webhooks to Skald?
Calendly, Cal.com, HubSpot, Typeform and Stripe each have their own signed hook. Zapier, Make, n8n and form plugins post to the json hook. Your own site's server posts to the lead hook, or uses a one-file helper for PHP, Node or Python, or the WordPress plugin.
How does Skald know a webhook is real?
Each hook has its own secret. Skald checks the message's signature with it before it keeps anything, and refuses a time more than 5 minutes off its own clock. No-code tools may send the secret as a plain key, Authorization: Bearer, on the json and lead hooks only. A wrong key is refused like a bad signature.
What happens when a tool sends the same webhook twice?
Nothing is counted twice. Skald keeps each conversion once per tool, reference and stage. A repeat is answered OK and shows as already had it in Last deliveries. Cal.com and Typeform sign no time, so Skald also remembers each of their messages for 30 days and ignores an exact repeat.
Can Skald send webhooks out?
Yes. Add an HTTPS address under Outgoing webhooks and tick the events: conversions by stage, abandoned starts, leads won or lost, AI reading changes and alert.opened. Each message is signed, and never holds a name or an email. Only events after you add the webhook are sent.
What does Skald keep from a webhook?
The action, its stage, the time, the tool and its own reference, the visitor ID when visitor IDs are on, and the source, campaign, landing page, country and device when known. IP addresses, browser strings, phone numbers, form answers and customer details are always dropped. Names and emails are kept only when the site's setting keeps them.
How do I test a webhook?
Press Send a test event in the tool's box. Skald signs a sample, checks it, reads it, then keeps nothing and counts nothing, and says what a real message would keep. To check the other tool's side, use its own test button and look at Last deliveries.
$ tail -f access.log | skald
See what AI does with your site. Free for 30 days.
No card. We set up hosted Skald for you within one working day, or you self-host it free. Every line of your log, sorted and added up.