Put it all together: build a complete lead capture pipeline — from form submission to CRM entry, welcome email, Slack notification, and dashboard row.
Goal: When a visitor fills out a contact form on your website:
[Website Form]
|
| POST /webhook/lead-capture
v
[1] Webhook Trigger
|
v
[2] Code — Validate & Transform
|
+---(invalid)---► [Respond 400 Bad Request]
|
v (valid)
[3] Google Sheets — Append Row
|
v
[4] Gmail — Send Welcome Email
|
v
[5] Slack — Notify Sales Channel
|
v
[6] Respond to Webhook — 200 OK
Node type: Webhook HTTP Method: POST Path: lead-capture Authentication: Header Auth Header Name: X-Form-Secret Header Value: my-form-secret-2024 Response Mode: Using Respond to Webhook node
// Run Once for All Items
const body = $input.first().json.body;
// Validate required fields
const required = ['name', 'email', 'message'];
for (const field of required) {
if (!body[field] || body[field].trim() === '') {
throw new Error(`Missing required field: ${field}`);
}
}
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(body.email)) {
throw new Error('Invalid email format');
}
// Normalize & return
return [{
json: {
name: body.name.trim(),
email: body.email.toLowerCase().trim(),
message: body.message.trim(),
phone: body.phone?.trim() || '',
source: body.source || 'website',
submittedAt: new Date().toISOString()
}
}];
Node type: Google Sheets
Operation: Append Row
Credential: My Google OAuth
Spreadsheet ID: (your sheet ID from URL)
Sheet Name: Leads
Columns:
name = {{ $json.name }}
email = {{ $json.email }}
message = {{ $json.message }}
phone = {{ $json.phone }}
source = {{ $json.source }}
submitted = {{ $json.submittedAt }}
Node type: Gmail
Operation: Send Email
Credential: My Gmail OAuth
To: {{ $json.email }}
Subject: Thanks for reaching out, {{ $json.name }}!
Body (HTML):
<p>Hi {{ $json.name }},</p>
<p>Thank you for contacting us! We received your message:</p>
<blockquote>{{ $json.message }}</blockquote>
<p>Our team will get back to you within 1 business day.</p>
<p>Best regards,<br>The Team</p>
Node type: Slack
Operation: Send a Message
Credential: My Slack App
Channel: #sales-leads
Message:
*New Lead Received* :tada:
*Name:* {{ $json.name }}
*Email:* {{ $json.email }}
*Source:* {{ $json.source }}
*Message:* {{ $json.message }}
_Received: {{ $now.toFormat('MMM d, yyyy HH:mm') }}_
Node type: Respond to Webhook
Response Code: 200
Response Body Type: JSON
Body:
{
"success": true,
"message": "Thank you! We will be in touch soon."
}
{"success":true,"message":"..."}curl -X POST https://your-n8n.com/webhook-test/lead-capture \
-H "Content-Type: application/json" \
-H "X-Form-Secret: my-form-secret-2024" \
-d '{
"name": "Test User",
"email": "test@example.com",
"message": "Hello, I am interested in your services.",
"source": "website"
}'
# Export workflow as JSON backup:
Workflow Editor → ⋮ menu → Download
# Saves a .json file you can commit to git
# Import a workflow:
n8n Home → Workflows → Import from File
# JSON structure overview:
{
"name": "Lead Capture Pipeline",
"nodes": [...], // all node configs
"connections": {...}, // how nodes connect
"settings": {
"errorWorkflow": "abc123",
"timezone": "UTC"
}
}
# Best practice: keep workflow JSON in a /n8n-workflows/ git repo
# Tag versions: v1.0-stable, v1.1-add-email, etc.
# Activate the workflow for production: 1. Save the workflow (Ctrl+S) 2. Toggle "Active" switch (top right) → ON 3. The production webhook URL is now live 4. Copy the Production URL (different from Test URL) 5. Update your website form action to the Production URL # For scheduled workflows: - Use Schedule Trigger instead of Webhook - Set up the cron: 0 9 * * 1-5 (weekdays 9am) - Activate the workflow - Monitor first few executions in the Executions log
EXECUTIONS_DATA_MAX_AGE=30 to prevent log bloatYou've covered all 8 lessons: intro, triggers, data & expressions, HTTP, credentials, error handling, AI agents, and the full capstone project.
You now have the foundation to automate almost any business workflow with n8n.