Lead Capture Kitfor n8n
Get the kit

Set it up

Connect your website

Any form that can send a POST request works. Field names are flexible, so most builders work without renaming anything.

#The address and format

Production URL https://YOUR-N8N-DOMAIN/webhook/lead-capture
Test URL https://YOUR-N8N-DOMAIN/webhook-test/lead-capture (one request per Execute workflow click)
Method POST
Body JSON, or a normal HTML form (application/x-www-form-urlencoded)
UTM tags Read from the body or the URL query string

Replace YOUR-N8N-DOMAIN with your n8n address. The production URL only works after you publish the main workflow.

#Field names it understands

You don't have to rename your form fields. The Normalize & Validate node accepts all of these:

Field Also accepted
name full_name, fullName, Full Name, your-name, or first_name + last_name
email Email, email_address, your-email, E-mail
phone mobile, phone_number, contact_number, Phone / Mobile, your-phone
company business, organization, business_name, Company / Business
message msg, comments, inquiry, your-message, How can we help?
source lead_source (defaults to Config default_source)
utm_source … utm_content Also read from the page URL's query string
page_url page, pageUrl, url (falls back to the Referer header)
website Honeypot. Keep it empty and hidden; bots fill it in
form_started_at Optional time the form was opened (Unix seconds or milliseconds). Faster than min_fill_seconds counts as spam

A lead needs a name and at least an email or a phone number.

#Plain HTML form

No JavaScript needed. After submitting, the browser shows the JSON reply, so this suits quick tests and simple sites.

HTML
<form action="https://YOUR-N8N-DOMAIN/webhook/lead-capture" method="POST">
  <input name="name" placeholder="Full name" required>
  <input name="email" type="email" placeholder="Email" required>
  <input name="phone" placeholder="0917 123 4567">
  <input name="company" placeholder="Business name">
  <textarea name="message" placeholder="How can we help?" required></textarea>
  <!-- honeypot: hidden from people, bots fill it -->
  <input name="website" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px">
  <input type="hidden" name="source" value="website">
  <button>Send</button>
</form>

The visitor stays on your page, sees your thank-you message, and the form passes UTM tags, the page address and the start time for the speed check.

HTML
<form id="lead-form">
  <input name="name" placeholder="Full name" required>
  <input name="email" type="email" placeholder="Email" required>
  <input name="phone" placeholder="0917 123 4567">
  <input name="company" placeholder="Business name">
  <textarea name="message" placeholder="How can we help?"></textarea>
  <input name="website" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px">
  <button>Send</button>
  <p id="lead-msg" role="status"></p>
</form>
<script>
  const f = document.getElementById('lead-form');
  const started = Date.now();
  f.addEventListener('submit', async (e) => {
    e.preventDefault();
    const data = Object.fromEntries(new FormData(f));
    const q = new URLSearchParams(location.search);
    ['utm_source','utm_medium','utm_campaign','utm_term','utm_content']
      .forEach(k => { if (q.get(k)) data[k] = q.get(k); });
    data.page_url = location.href;
    data.form_started_at = started;
    const res = await fetch('https://YOUR-N8N-DOMAIN/webhook/lead-capture', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    const out = await res.json().catch(() => ({}));
    document.getElementById('lead-msg').textContent =
      out.formSubmittedText || (res.ok ? 'Thanks!' : 'Please try again.');
    if (res.ok) f.reset();
  });
</script>

#Website builders

Builder Where to set it
WordPress: Contact Form 7, WPForms, Elementor Pro, Fluent Forms Use the builder's Webhook action, or a webhook add-on → the production URL → POST. CF7's your-name, your-email and your-message already match.
Webflow Site settings → Forms → Form submission webhooks, or Integrations → Webhooks with the trigger Form submission.
Framer, Wix, Squarespace, Carrd The form's Send to webhook or custom URL setting where your plan allows it, or paste the JavaScript form into a custom-code block.
Typeform, Tally, Jotform Add a webhook pointing at the production URL. Nested payloads may need one extra Edit Fields node before Config to flatten them.
Facebook Lead Ads Use a small parent workflow; see the FAQ.

#Try it from a terminal

Terminal
curl -sS -X POST "https://YOUR-N8N-DOMAIN/webhook/lead-capture" \
  -H "Content-Type: application/json" \
  -d '{"name":"Angelo Bautista","email":"angelo.bautista@example.com","phone":"0917 555 0199","message":"Hello from curl","website":""}'

#What your website gets back

Case HTTP Body
Saved, new lead 200 {"ok":true,"lead_id":"LC-…","duplicate":false,"status":"new","formSubmittedText":"…"}
Saved, repeat lead 200 {"ok":true,"lead_id":"LC-…","duplicate":true,"status":"returning", …}
Spam 200 {"ok":true,"formSubmittedText":"…"} and nothing is saved
Invalid 422 {"ok":false,"errors":["email looks invalid"],"formSubmittedText":"Please check: …"}
Google Sheets down 503 {"ok":false,"error":"temporarily_unavailable", …} and the error handler runs

Show formSubmittedText to the visitor. You can change its wording in Config (form_thank_you_text).

Lead Capture Kit for n8n: website enquiries saved to Google Sheets, de-duplicated, thanked and sent to your team chat.

Checked against n8n 2.47.3. n8n, Google Sheets, Gmail, Telegram, Slack and Discord are trademarks of their owners; this kit is not affiliated with them. Sample data is fictional.