Skip to content
New storyWe built Skald to count visitors. It caught an AI-key thief.
SkaldEvery visit, truly told.

Lead attribution · your server

A lead file from your backend: one file, one line, every lead

A lead file from your backend is the quickest way for your own server to tell Skald about each lead: download one file for PHP, Node or Python, and call one function after the form is saved.

A lead file from your backend is a small file Skald gives you for your site's language. It signs each lead with your hook's secret, posts it to Skald, waits at most 3 seconds, and never throws, so a form never breaks because of Skald.

30-day free trial · no card · we set it up within one working day · free to self-host

// your own code saved the entry: $entry_id
require_once __DIR__ . '/skald-lead.php';
skald_lead($entry_id, 'contact', $email, $name);
true Skald kept the lead signed with SKALD_LEAD_SECRET · waits at most 3 s · never throws

Sample code. One file next to your code, one call after the entry is saved. The PHP file also reads the visitor ID from the form's skald_vid field or cookie by itself.

[01] it never breaks a form

What happens to your form when Skald is slow or down? The file gives up within 3 seconds.

The lead file sends one signed POST and waits at most 3 seconds. It never throws: it returns true when Skald kept the lead, and false for anything else, so your form carries on. Pick what goes wrong and watch each file's clock. Every lead lands in your lead attribution.

break something
  1. PHP with curl
    true · 0.04 s
  2. Node 18 or later
    true · 0.04 s
  3. Python 3.8 or later
    true · 0.04 s

Skald answers 200 and kept the lead. Each file returns true.

Sample timings: real ones depend on your network. The 3 seconds still come out of your request's time: call the function after you answer the visitor, or from a queue, if that matters. The files do not send again by themselves.

[02] no lead lost

Check that Skald has every lead your server sent, and send the missing again

A lead lost on the way is never lost for good. Your server asks Skald which leads it holds, signed with the same secret, compares them with its own list, and sends the missing ones again with their own time. A resend of a lead already kept changes nothing.

your server's leads since Monday · sample

  1. L-1001demoMon 09:12
  2. L-1002contactMon 11:40
  3. L-1003signupTue 08:05
  4. L-1004contactTue 16:22
  5. L-1005demoWed 10:01
  6. L-1006signupWed 13:30
  7. L-1007contactThu 09:47
  8. L-1008demoThu 15:15
ask Skald

the request

GET /traffic-hooks/example.com/leads?since=2026-10-19T00%3A00%3A00Z&limit=500
X-Skald-Signature: t=1792843200,v1=<hex HMAC-SHA256 of the signed line>

signed: 1792843200.GET /traffic-hooks/example.com/leads?since=2026-10-19T00%3A00%3A00Z&limit=500

Press Ask Skald. Skald answers with each lead's reference, action, stage, time, label, test mark and when it arrived. Never a name, an email, an address or a visitor ID.

Sample leads; t is the time of the request, signed over the path and the query exactly as sent. Up to 500 rows a page, with a cursor for the next. It lists only the leads from this hook, and Skald keeps them 400 days by default.

[03] same server, behind Cloudflare

Your backend runs on the same server as Skald? Post to the local address.

When the public address goes through Cloudflare, a server that posts to its own public address can be refused with a 403, error 1010 or a bot check: Cloudflare takes the post for a bot. Post to Skald's local address instead, or allow the path in Cloudflare. The signature is the same either way.

pick a road
YOUR SERVER your backendthe skald-lead file Skald127.0.0.1:8080 Cloudflarepublic address ✕

the file posts tohttps://stats.example.com/traffic-hooks/example.com/lead

can be refused 403, error 1010 or a bot check: the file returns false.

[04] backfill

Backfill old leads on the right day: send each with its time and its offset

A lead sent late lands on the day in its at, not the day it arrived. Type a time, or pick one, and see the day it lands on in the site's own zone.

the site's time zone

try a time

arrived Sat 24 Oct, 11:00 in the site's zone · sample

  1. Thu 22 Oct
  2. Fri 23 Oct
  3. Sat 24 Oct

kept on Thu 22 Oct, 23:30 in the site's zone (03:30 UTC on 23 Oct)

Sample arrival, Saturday 24 October 2026 at 15:00 UTC. Times are read the way Skald reads them: ISO text, or Unix seconds (milliseconds when the number is that big). Send backfills slowly: 60 a minute for the hook, or up to 100 at once through the json hook.

[05] set up and limits

Set up the lead file in four steps

Make the secret, keep it on the server, add the file, then test it.

  1. Make secret. Skald: Settings > Integrations > Your site's server (lead) > Make secret.
  2. Keep the secret on the server. Set SKALD_LEAD_SECRET in its environment, the settings your server hands to your code when it starts, kept out of your files. Every file reads it first.
  3. Download the file. skald-lead.php, skald-lead.cjs or skald_lead.py. Call its one function after the entry is saved.
  4. Test it. Press Send a test event: read, never kept. Then send a real lead and look at Last deliveries. Your team's own tests go with "test": true: listed, never counted.

What it does not do

  • It sends once. When it returns false, sending again is your code's job, and [02] finds what is missing.
  • It waits up to 3 seconds inside your request when Skald is slow.
  • Journeys need the visitor ID. The page must pass it (the PHP file reads skald_vid by itself; Node and Python take it as vid), and visitor IDs must be on for the site. They are off by default.
  • The same lead sent by this file and by Zapier counts twice. Send each lead one way.
  • A file downloaded with the secret in it must stay out of public places and public code repositories.
  • A time with no offset is a guess: Skald reads it in the site's zone.

questions

Lead file from your backend FAQ

Straight answers, including what Skald does not do.

Which languages are there lead files for?

PHP (skald-lead.php), Node 18 or later (skald-lead.cjs, which also loads from an ES module) and Python 3.8 or later (skald_lead.py). WordPress has its own plugin. Any other language can sign and post the JSON itself: the help page has the exact body and signature, with curl, Node, Python and PHP examples.

Can the lead file break my form?

No. Each function waits at most 3 seconds, never throws, and returns true when Skald kept the lead. When it returns false, your code can send the lead again later. A repeat is never counted twice.

Where does the secret go?

Best in an environment variable on your server named SKALD_LEAD_SECRET: every file reads it first. A file downloaded right after you made the secret holds it and works as it is, but keep that file out of public places and public code repositories. Never put the secret in a web page.

How do I join a lead to the visitor's journey?

With Skald's script tag on the page and visitor IDs on, the page knows the visitor ID as skald('id'). Bring it to your server in a hidden form field named skald_vid. The PHP file reads that field, and the skald_vid cookie, by itself. In Node and Python, pass it as vid.

How do I send leads my team made as tests?

Send them with test set to true, for example your team's own accounts or a QA run. Skald keeps and lists them, and never counts them. Leads already sent can be marked test later with the signed leads/test call, or with Mark as test in the dashboard.

My backend is on the same server as Skald, behind Cloudflare. What address do I post to?

Skald's local address, not the public one: Cloudflare can block a server that posts to its own public address. In Docker that is http://127.0.0.1 with the port you published; with the install script, port 8766. The signature is the same either way.

$ 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.

Start free trial Live demo