AI Lead Scorer with n8n Automation

Build an AI workflow that scores inbound leads and alerts your team instantly.

Introduction

30 Second Summary

Every business gets inquiries. Some are from dream customers ready to place a bulk order. Others are students asking about career advice.

In this project, you will build an AI-powered lead scoring workflow that automatically evaluates inbound inquiries against your ideal customer profile, scores them in seconds, and routes hot leads straight to your team.

What You'll Build

Picture sending a lead inquiry to a URL and watching it come back scored 0-100, categorized into a tier, logged in a spreadsheet, and pinged to your Slack channel within seconds.

By the end of this project, you'll have:

  • A live webhook endpoint that receives lead inquiries and returns AI-generated scores with tier classifications, reasoning, and suggested next actions.
  • A Google Sheet automatically populated with every scored lead, including timestamps, AI reasoning, and a team-ready Status column for follow-up tracking.
  • A Slack notification that fires instantly when a Hot lead arrives, so your team can respond in minutes instead of hours.
  • Secret Mission: Build a daily digest workflow that posts a morning summary to Slack with total leads and the Hot/Warm/Cold breakdown.

Are there any prerequisites?

This project assumes you have basic familiarity with n8n (you have used it before). You will also need a Google account and access to a Slack workspace where you can install a bot.

During setup, you will create an OpenAI API key with a small pay-as-you-go balance ($5 is plenty for this project).

Before We Start

Before We Start...

Before we dive in, let's lock in what you're about to build and why it matters.

Set Up Credentials and Google Sheet

Your lead scoring workflow connects four services: n8n orchestrates the automation, OpenAI scores the leads, Google Sheets logs the results, and Slack alerts the team.

Before you can build anything, each of these services needs a credential saved in n8n. Getting credentials connected first means every subsequent step produces visible results immediately.

In this step, get ready to:
  • Sign up for n8n Cloud and log into the workflow editor.
  • Save your OpenAI and Google Sheets credentials in n8n, and create your lead tracking spreadsheet.
  • Create a Slack app, save its credential in n8n, and set up a notification channel.
Sign up for n8n Cloud

n8n Cloud is where your workflow will live and run. The free trial gives you 2,500 executions, which is more than enough for this project.

  • Open https://app.n8n.cloud/register in your browser.
  • Create your account (no credit card required).
  • Once your instance is provisioned, click the link in your confirmation email or follow the on-screen prompt to open the n8n editor.

You should see the n8n editor canvas with a blank workspace and a left sidebar for navigating workflows, credentials, and executions.

Don't see the editor?

n8n Cloud instances can take 1-2 minutes to provision after sign-up. Refresh the page if you see a loading screen for more than a minute.

Check your email for a verification link if you are stuck on a confirmation screen.

Help me get into the n8n Cloud editor

Create your OpenAI and Google Sheets credentials

Your workflow will call OpenAI to score each lead, so you need an API key with a small pay-as-you-go balance. You also need Google Sheets access to log every scored lead into a team-ready spreadsheet.

  • Open https://platform.openai.com/api-keys in a new tab.
  • Click Create new secret key.
  • Give it a name like n8n-lead-scorer and click Create secret key.
  • Copy the key immediately. You will not be able to see it again after closing the dialog.
  • If you do not already have a pay-as-you-go balance, navigate to Settings > Billing in OpenAI and add $5 (that is more than enough for this project).

Why do I need a pay-as-you-go balance?

OpenAI charges per API call. For this project using gpt-4o-mini, each lead score costs a fraction of a cent. Your total spend will likely be under $0.05 for the entire project.

Now save this key in n8n as a credential.

  • Switch back to your n8n editor tab.
  • Click Credentials in the left sidebar.
  • Click Add Credential.
  • Search for OpenAI and select it.
  • Paste your API key into the API Key field.
  • Click Save. You should see a green Connected status confirming the key works.

Seeing a connection error?

Double-check that you copied the full API key (it starts with sk-). Make sure your OpenAI account has a positive pay-as-you-go balance. A $0 balance will cause authentication to fail.

Help me fix my OpenAI credential connection

Next, create the Google Sheets credential.

  • Click Add Credential again.
  • Search for Google Sheets and select it.
  • Click Sign in with Google. This uses n8n Cloud's Managed OAuth, so there is no Google Cloud Console setup needed.
  • Authorize n8n to access your Google account when prompted.
  • Click Save. Confirm you see the green Connected status.

Now create the Google Sheet that will store your scored leads.

  • Open Google Sheets in a new tab.
  • Create a new blank spreadsheet.
  • Rename it to Lead Scores by clicking the title in the top left.
  • In Row 1, enter these exact column headers across cells A1 through K1:
Timestamp | Lead Name | Company | Industry | Message | Score | Tier | Reasoning | Next Action | Needs Follow-up | Status

What are these columns for?

Each column maps to a specific piece of data your AI workflow will produce. Score is the 0-100 numeric rating. Tier is Hot, Warm, or Cold. Reasoning explains why the AI gave that score.

Status is a manual column the marketing team uses to track follow-ups. Your workflow will pre-fill it with "New" so the team always has a starting point.

Your spreadsheet should now show 11 headers in Row 1 with no data below them.

Create your Slack app and credential

Your workflow will send a Slack message whenever a Hot lead arrives. To do this, you need a Slack app with the right permissions installed to your workspace.

  • Open https://api.slack.com/apps in a new tab.
  • Click Create New App.
  • Select From a manifest.
  • Select the workspace where you want to install the app, then click Next.
  • Select the JSON tab and replace the default content with the manifest below.
{
  "display_information": { "name": "n8n integration" },
  "features": {
    "bot_user": { "display_name": "n8n integration" }
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "channels:read", "channels:history", "chat:write",
        "files:read", "files:write",
        "groups:read", "groups:history",
        "im:read", "im:history",
        "mpim:read", "mpim:history",
        "reactions:read", "reactions:write",
        "usergroups:read", "usergroups:write",
        "users.profile:read", "users:read"
      ]
    }
  },
  "settings": {
    "org_deploy_enabled": false,
    "socket_mode_enabled": false,
    "token_rotation_enabled": false
  }
}

What does this manifest do?

This manifest creates a bot app with the scopes n8n recommends. The two scopes you need for this project are chat:write (to post messages) and channels:read (to find your channel).

The other scopes are included so the credential works with any Slack node action you might use later.

  • Click Next.
  • Review the summary, then click Create.
  • In the left menu, click OAuth & Permissions.
  • Click Install to Workspace.
  • Click Allow when prompted.
  • Copy the Bot User OAuth Token (it starts with xoxb-).

Now save this token in n8n.

  • Switch back to your n8n editor tab.
  • Click Credentials in the left sidebar.
  • Click Add Credential.
  • Search for Slack and select it.
  • Select Access Token as the authentication method.
  • Paste your Bot User OAuth Token into the Access Token field.
  • Click Save. Confirm you see the green Connected status.

Finally, create the Slack channel your bot will post to.

  • Open your Slack workspace.
  • Create a new channel called #leads.
  • Invite your bot to the channel by typing /invite @n8n integration in the channel message field and pressing Enter.

You should see a confirmation message in the channel that the app has been added.

Bot not showing up in the invite list?

Make sure you completed the Install to Workspace step in the Slack API dashboard. Until the app is installed, it will not appear in your workspace.

If the slash command does not work, click the channel name at the top, go to Integrations, and click Add an App to find n8n integration.

Help me get my Slack bot into the #leads channel

Verify all three credentials

Before you move on, confirm that all your credentials are working. What do you expect to see when you check the Credentials page?

  • In n8n, click Credentials in the left sidebar.

You should see three saved credentials (OpenAI, Google Sheets, Slack) each showing a green Connected status.

Your environment is fully wired up. Next up, you will build your first workflow node and see what happens when AI scores a lead without any structure enforced.

Build the Webhook Trigger and Freeform AI Call

Your credentials are connected and your Google Sheet is ready to receive data. Now it's time to build the workflow that actually receives inbound leads and scores them with AI.

In this step, you'll wire up a webhook that listens for incoming leads and feeds them to an AI model for scoring. You'll deliberately leave the AI's output as freeform text to see what happens when automation meets unstructured prose.

In this step, get ready to:
  • Create a webhook-triggered workflow that listens for incoming lead data.
  • Connect an AI model that scores leads against a manufacturing ICP.
  • Send a test lead and observe the AI's freeform response.
Create a new workflow with a Webhook trigger

A webhook is a URL that waits for incoming data. When a lead inquiry arrives at this URL, your workflow springs to life and processes it.

  • In the n8n editor, click the + button in the top-right corner and select Workflow to create a new blank workflow.
  • Click the workflow name at the top of the canvas and rename it to Lead Scorer.
  • Click Add first step on the canvas to open the node search panel.
  • Search for Webhook and select the Webhook node.
  • In the Webhook node settings, set HTTP Method to POST.
  • Set the Path field to lead-score.
  • Look at the top of the Webhook node panel for the Test URL field. Copy this URL and save it somewhere handy. You'll need it shortly.

What is the Test URL?

n8n gives each Webhook node two URLs: a Test URL (for development) and a Production URL (for live use). The Test URL only works while you're actively listening for test events in the editor.

Don't see the Webhook node?

Make sure you're searching in the trigger nodes section. The Webhook node is a trigger, so it appears when you click Add first step rather than through the general node connector.

If you still can't find it, help me find the Webhook trigger node in n8n.

Add the AI scoring chain

The Basic LLM Chain node sends a prompt to an AI model and returns the response. You'll connect it to OpenAI's gpt-4o-mini model and write a prompt that describes your manufacturing ICP.

  • Close the Webhook node panel and click the + connector on the right side of your Webhook node.
  • Search for Basic LLM Chain and select it.
  • The Basic LLM Chain node opens with a model attachment point at the bottom. Click the + Model connector and select OpenAI Chat Model.
  • In the OpenAI Chat Model sub-node, select your saved OpenAI credential.
  • Set Model to gpt-4o-mini.
  • Close the sub-node to return to the Basic LLM Chain settings.
  • In the Prompt dropdown, select Define below.
  • Paste the following prompt into the Prompt (User Message) field:
You are a lead scoring assistant for a B2B trade and manufacturing business.

Evaluate the following inbound lead against our Ideal Customer Profile (ICP):

{{ $json.body }}

Our ICP criteria:
- Industry: Trade, construction, and manufacturing score highest
- Company size: 50-500 employees is our sweet spot
- Order/project value signals: Look for bulk orders, large projects, infrastructure work
- Urgency keywords: quote, urgent, bulk order, deadline, ASAP, timeline
- Location: Australia and New Zealand preferred

Score this lead from 0-100 based on how well they match our ICP. Provide:
1. A numeric score (0-100)
2. A tier (Hot, Warm, or Cold)
3. Your reasoning
4. A suggested next action for the sales team

What does this prompt do?

The expression {{ $json.body }} pulls in the entire JSON body from the incoming webhook POST request. The AI sees the raw lead data (name, company, message) alongside your ICP criteria and returns its assessment.

Notice you're asking for specific outputs (score, tier, reasoning, next action) but you're not enforcing any structure on the response. The AI can format its answer however it wants.

Seeing a 'No prompt specified' error?

Make sure the Prompt dropdown is set to Define below and that you pasted the text into the Prompt (User Message) field that appears underneath it.

If the field is empty or set to 'Take from previous node automatically', the chain has no prompt to send. Help me configure the Basic LLM Chain prompt in n8n.

Your canvas should now show two connected nodes: Webhook flowing into Basic LLM Chain, with the OpenAI Chat Model attached below the chain node.

Test with a sample lead

Time to fire a test lead at your webhook and see how the AI responds. You'll use curl to simulate an inbound inquiry from a steel fabrication company.

  • Click on your Webhook node to open its panel.
  • Click Listen for test event at the top of the panel. The node now listens for incoming data for 120 seconds.

Keep the n8n tab open

You need to keep the editor tab open and visible while listening. Open a new terminal window (or a new browser tab for Postman) to send your test request.

  • Open a terminal window by pressing Cmd+Space (macOS) or the Windows key (Windows), then type Terminal and press Enter.
  • Send a test lead to your webhook by running this command:
curl -X POST [[WEBHOOK_TEST_URL="your webhook Test URL"]] -H "Content-Type: application/json" -d '{"name": "Dave Wilson", "company": "Wilson Steel Fabrication", "industry": "Manufacturing", "company_size": "50-200", "message": "Need urgent quote for bulk order of structural steel beams for new warehouse project. Timeline is 3 weeks.", "location": "Sydney, Australia"}'

What does this curl command do?

This simulates a lead inquiry arriving at your webhook. It sends a POST request with JSON data describing Dave Wilson from Wilson Steel Fabrication, who needs an urgent bulk order of structural steel beams.

In a real scenario, this data would come from a web form or CRM integration. For testing, you're sending it manually.

Windows users

If curl does not work in PowerShell, use Git Bash instead. Alternatively, you can use Postman to send the POST request with the same JSON body.

Before you switch back to n8n, take a moment to predict: what format do you think the AI's response will come back in? A tidy JSON object, or something else?

  • Switch back to the n8n editor tab. You should see the workflow executed successfully with green indicators on both nodes.
  • Click on the Basic LLM Chain node to open its output panel.

Look at what came back. The AI's response is a blob of conversational prose.

The score is buried somewhere in a sentence like "I would rate this lead an 87 out of 100." The tier might appear as "This is a Hot lead" one time and "Tier: Hot" the next. There is no consistent structure.

This is the problem

You cannot reliably extract score = 87 or tier = Hot from this response. Every run produces slightly different formatting.

A downstream Switch node needs a clean tier field to route on. Google Sheets needs separate columns for each value. Freeform text gives you none of that.

This is the expected result. You deliberately asked the AI for information without telling it how to format the answer. The next step introduces a fix that forces the AI to return clean, individually addressable JSON fields every single time.

You've proven the core loop works. A lead arrives, the AI reads it, and it produces a thoughtful score. The problem is the packaging. Next up, you'll swap in a Structured Output Parser that forces the AI into a clean JSON schema your workflow can actually route on.

Enforce Structured JSON Output

In the previous step, you saw the core problem with asking an AI to score a lead without constraints. The response came back as conversational prose with the score buried in a sentence and the tier mentioned inconsistently.

No downstream node can reliably extract score = 87 or tier = Hot from a paragraph of text. The fix is to force the AI to return exactly the fields you need, in the same JSON structure, every single time. This is the pattern that makes AI outputs usable in automation.

In this step, get ready to:
  • Replace the freeform Basic LLM Chain with one that enforces structured output.
  • Define a JSON schema and write a full ICP scoring prompt.
  • Test that the AI returns clean, individually addressable JSON fields.
Replace the freeform LLM Chain with structured output

The existing Basic LLM Chain has no output constraints. You need a fresh one with the Require Specific Output Format setting enabled and a Structured Output Parser attached.

  • In the n8n editor, select the existing Basic LLM Chain node on your canvas.
  • Press Delete (or Backspace) to remove it from the canvas.
  • Click the + button on the Webhook node's output connector.
  • Search for Basic LLM Chain and add it to your workflow.
  • Open the new Basic LLM Chain node. Click the Model attachment point at the bottom and add an OpenAI Chat Model sub-node.
  • In the OpenAI Chat Model sub-node, select your OpenAI credential and choose the model gpt-4o-mini.
  • Return to the Basic LLM Chain node settings. Scroll down and toggle Require Specific Output Format to on.
  • A new Output Parser attachment point appears at the bottom of the node. Click it and select Structured Output Parser.

You should now see the Basic LLM Chain with two sub-nodes connected beneath it: the OpenAI Chat Model and the Structured Output Parser.

Why delete and re-add the node?

Starting with a fresh Basic LLM Chain ensures no leftover prompt text or configuration from the freeform version interferes. It also gives you a clean slate for the structured output settings.

Configure the schema and scoring prompt

The Structured Output Parser needs a schema that defines exactly which fields the AI must return. You will generate the schema from a JSON example, then write a prompt that tells the AI how to score leads against your manufacturing ICP.

  • Open the Structured Output Parser sub-node.
  • Set Schema Type to Generate from JSON Example.
  • Paste the following example into the JSON Example field:
{
  "score": 85,
  "tier": "Hot",
  "reasoning": "Manufacturing company with 50-200 employees requesting bulk structural steel. Urgency signals: 'urgent', 'bulk order', '3 weeks timeline'. High-value project indicator.",
  "next_action": "Call within 2 hours - hot manufacturing lead with urgent timeline",
  "needs_followup_info": false
}

How does Generate from JSON Example work?

n8n reads the property names and types from your example (number, string, boolean) and builds a schema from them. It ignores the actual values. Every field is treated as mandatory, so the AI must return all five fields every time.

  • Close the Structured Output Parser and return to the Basic LLM Chain node.
  • Set the Prompt source to Define below.
  • Paste the following ICP scoring prompt into the Prompt field:
You are a lead scoring AI for a B2B trade and manufacturing business. Score the following lead inquiry on a scale of 0-100 based on our Ideal Customer Profile (ICP).

Scoring criteria:
- Industry vertical: Trade, construction, and manufacturing score highest (60-100). Professional services score medium (30-60). Consumer, student, or unrelated industries score low (0-30).
- Company size: 50-500 employees is the sweet spot (high score). Under 50 or over 500 scores lower.
- Order/project value signals: Mentions of bulk orders, large quantities, project-scale work, or specific material needs increase score.
- Urgency keywords: Words like "urgent", "quote", "bulk order", "deadline", "ASAP", or specific timelines increase score significantly.
- Location: Australia and New Zealand score highest. Asia-Pacific scores medium. Other regions score lower.

Assign a tier based on score:
- Hot: 70-100
- Warm: 40-69
- Cold: 0-39

Set needs_followup_info to true if the lead is missing critical information (company size, specific requirements, or timeline) that would change the score significantly.

Lead inquiry data:
{{ $json.body }}

What does this prompt do?

The prompt defines your manufacturing ICP scoring rubric. It weights industry vertical, company size (50-500 is the sweet spot), order value signals, urgency keywords like "urgent" or "ASAP", and geographic proximity.

The expression {{ $json.body }} injects the raw lead data from the Webhook into the prompt. The needs_followup_info field flags leads where the AI lacks confidence due to missing data.

  • Click Back to canvas to close the node panel and save your changes.
Test the structured output

Time to see the difference. You will send the same Dave Wilson test lead you used in the previous step, but this time the output parser forces the AI to return clean JSON.

  • Click on the Webhook node and select Listen for test event.

Before you run the test, think about what you expect to see this time. Will the output be a paragraph of prose like before, or something different?

  • In a separate terminal window, send the same test lead by running this command:
curl -X POST [[WEBHOOK_URL="your n8n webhook test URL"]] -H "Content-Type: application/json" -d '{"name": "Dave Wilson", "company": "Wilson Steel Fabrication", "industry": "Manufacturing", "company_size": "50-200", "message": "Need urgent quote for bulk order of structural steel beams for new warehouse project. Timeline is 3 weeks.", "location": "Sydney, Australia"}'

Switch back to the n8n editor. Click on the Basic LLM Chain node to view its output.

This time, instead of a wall of prose, you see clean JSON with individually addressable fields: score (a number), tier (a string like "Hot"), reasoning (a string), next_action (a string), and needs_followup_info (a boolean). You can click into each field and reference it individually in downstream nodes.

Why is this better than the freeform version?

Every field is now a separate, predictable value. A Switch node can route on tier. A Google Sheets node can map score directly to a column. A Slack message can reference next_action without guessing where it appears in a paragraph.

Now test with a lead that has missing data to confirm the needs_followup_info flag works.

  • Click Listen for test event on the Webhook node again.
  • Send a vague, incomplete lead by running this command:
curl -X POST [[WEBHOOK_URL="your n8n webhook test URL"]] -H "Content-Type: application/json" -d '{"name": "Alex Thompson", "company": "Thompson Consulting", "industry": "Unknown", "message": "Hi, interested in learning more about your services. Can someone get back to me?"}'
  • Check the output of the Basic LLM Chain node.

This lead has no company size, no location, and a vague message with no urgency signals. You should see a low score, a "Cold" tier, and needs_followup_info set to true. The AI flagged this lead because missing data (company size, specific requirements, timeline) means the score could change significantly with more information.

Seeing an error instead of JSON output?

Make sure your OpenAI credential is connected to the OpenAI Chat Model sub-node and that you selected gpt-4o-mini as the model.

Confirm the Structured Output Parser is attached to the output parser slot (not the model slot). If you accidentally put it in the wrong attachment point, remove it and re-add it to the correct one.

Check that your JSON example in the parser has valid syntax. Even a missing comma or extra bracket will break the schema generation.

Your AI now returns predictable, routable data every time. Next up, you will connect a Switch node to route leads by tier and log every scored lead to your Google Sheet.

Route by Tier and Log to Google Sheets

Your AI now returns clean, structured JSON for every lead. But that data is sitting inside n8n with nowhere to go.

A marketing team cannot filter, sort, or act on data locked inside a workflow execution. In this step, you will reshape the AI output into the exact columns your Google Sheets expects, route leads by tier using a Switch node, and log every result so the team has a live dashboard they can action immediately.

In this step, get ready to:
  • Map AI output and webhook data into sheet-ready fields using an Edit Fields node.
  • Append scored leads to your Google Sheet automatically.
  • Route leads through a Switch node so Hot, Warm, and Cold leads follow different paths.
Map lead data to sheet-ready fields

The Basic LLM Chain outputs AI fields like score and tier, but your Google Sheet needs additional context: the lead's name, company, a timestamp, and a default status value. The Edit Fields (Set) node lets you combine data from multiple sources into one clean object.

  • In the n8n editor, click the + button on the output of your Basic LLM Chain node.
  • Search for Edit Fields and select the Edit Fields (Set) node.
  • Set Mode to Manual Mapping.
  • Click Add Field and add a field named timestamp. Switch its value to Expression mode and enter:
{{ $now.toISO() }}
  • Add a field named lead_name with the expression {{ $('Webhook').item.json.body.name }}.
  • Add a field named company with the expression {{ $('Webhook').item.json.body.company }}.
  • Add a field named industry with the expression {{ $('Webhook').item.json.body.industry }}.
  • Add a field named message with the expression {{ $('Webhook').item.json.body.message }}.

What are these expressions doing?

The $('Webhook') syntax reaches back to the Webhook node's output. Since the Edit Fields node isn't directly connected to the Webhook, you need this syntax to pull the original lead data forward.

The $now.toISO() expression generates the current date and time in ISO 8601 format, giving every row a precise timestamp.

  • Add a field named score with the expression {{ $json.score }}.
  • Add a field named tier with the expression {{ $json.tier }}.
  • Add a field named reasoning with the expression {{ $json.reasoning }}.
  • Add a field named next_action with the expression {{ $json.next_action }}.
  • Add a field named needs_followup_info with the expression {{ $json.needs_followup_info }}.
  • Add a field named status. Keep its value in Fixed mode and type New.
  • Scroll down to the bottom of the node panel and enable Keep Only Set Fields. This discards all other data and passes only your 11 clean fields downstream.

Why use Keep Only Set Fields?

Without this toggle, n8n passes all the raw AI output alongside your mapped fields. Enabling it ensures the Google Sheets node receives only the exact columns you defined. No extra noise.

Append scored leads to Google Sheets

Now that your data is shaped correctly, you need a node that writes each scored lead as a new row in your spreadsheet.

  • Click the + button on the output of your Edit Fields node.
  • Search for Google Sheets and add the node.
  • Set Resource to Sheet Within Document.
  • Set Operation to Append Row.
  • Under Document, select your Lead Scores spreadsheet.
  • Under Sheet, select the sheet (usually Sheet1 or the first tab).
  • Set Mapping Column Mode to Map Automatically. This matches your field names to the sheet column headers automatically.

Before you run the full workflow, think about what you expect to see. Will your Google Sheet populate with a new row?

  • Click Listen for test event on the Webhook node.
  • Send a test lead by running this curl command in your terminal:
curl -X POST [[WEBHOOK_TEST_URL="your webhook Test URL"]] -H "Content-Type: application/json" -d '{"name": "Dave Wilson", "company": "Wilson Steel Fabrication", "industry": "Manufacturing", "company_size": "50-200", "message": "Need urgent quote for bulk order of structural steel beams for new warehouse project. Timeline is 3 weeks.", "location": "Sydney, Australia"}'
  • Open your Lead Scores Google Sheet in a new tab.

You should see a new row with all 11 columns populated. The Timestamp shows the current time, Lead Name shows Dave Wilson, and the Status column reads New.

Row not appearing in your sheet?

  • Make sure your sheet column headers in Row 1 match the field names exactly (case-sensitive). For example, Lead Name must match lead_name in the Edit Fields node. If the mapping mode is set to Map Automatically, n8n matches by comparing field names against the header row.
  • Confirm you selected the correct spreadsheet and sheet tab in the Google Sheets node.
  • Check that Keep Only Set Fields is enabled. If disabled, extra fields from the AI output might confuse the automatic mapping.

Still stuck? Why isn't my Google Sheets node writing rows?

Add a Switch node to route leads by tier

Right now every lead takes the same path. You need conditional routing so that Hot leads can trigger a Slack alert in the next step, while all leads still land in the spreadsheet regardless of tier.

  • Delete the connection between the Edit Fields node and the Google Sheets node (click the line and press Delete).
  • Click the + button on the output of the Edit Fields node.
  • Search for Switch and add the node.
  • The Switch node opens in Rules mode by default. In the first routing rule, set the data type dropdown to String and the comparison to is equal to.
  • In the Value 1 field, switch to Expression mode and enter {{ $json.tier }}.
  • In the Value 2 field, type Hot.
  • Turn on Rename Output and name this output Hot.

What does the Switch node do?

The Switch node evaluates each incoming item against your rules and sends it out through the matching output. It works like a train track switch. Each rule creates a separate output connector you can wire to different downstream nodes.

  • Click Add Routing Rule to create a second rule.
  • Set it to String > is equal to. Value 1: {{ $json.tier }} (expression). Value 2: Warm. Rename the output to Warm.
  • Click Add Routing Rule again for a third rule.
  • Set it to String > is equal to. Value 1: {{ $json.tier }} (expression). Value 2: Cold. Rename the output to Cold.
  • Close the Switch node. You now see three output connectors labeled Hot, Warm, and Cold.
  • Drag a connection from the Hot output to the Google Sheets node.
  • Drag a connection from the Warm output to the same Google Sheets node.
  • Drag a connection from the Cold output to the same Google Sheets node.

Why connect all three outputs to the same node?

Every lead gets logged regardless of tier. The routing exists so you can additionally wire the Hot output to a Slack alert in the next step. The Switch node lets one output feed multiple downstream nodes.

Time to prove the routing works end-to-end. Before you send the test leads, predict: if you send a Hot lead, a Warm lead, and a Cold lead, will all three appear in your sheet or only the Hot one?

  • Click Listen for test event on the Webhook node.
  • Send a Hot lead by running:
curl -X POST [[WEBHOOK_TEST_URL="your webhook Test URL"]] -H "Content-Type: application/json" -d '{"name": "Dave Wilson", "company": "Wilson Steel Fabrication", "industry": "Manufacturing", "company_size": "50-200", "message": "Need urgent quote for bulk order of structural steel beams for new warehouse project. Timeline is 3 weeks.", "location": "Sydney, Australia"}'
  • Click Listen for test event again, then send a Warm lead:
curl -X POST [[WEBHOOK_TEST_URL="your webhook Test URL"]] -H "Content-Type: application/json" -d '{"name": "Sarah Chen", "company": "Chen Electrical Services", "industry": "Trade", "company_size": "10-50", "message": "Interested in getting a quote for electrical supplies for a small residential project.", "location": "Melbourne, Australia"}'
  • Click Listen for test event one more time, then send a Cold lead:
curl -X POST [[WEBHOOK_TEST_URL="your webhook Test URL"]] -H "Content-Type: application/json" -d '{"name": "Tom Nguyen", "company": "N/A", "industry": "Education", "company_size": "1", "message": "Hi, I am a university student researching supply chain careers. Could you tell me about your company?", "location": "Brisbane, Australia"}'
  • Open your Lead Scores Google Sheet and check for three new rows.

All three leads appear in your sheet. Each row shows a correct timestamp, the lead's details, a score, a tier (Hot, Warm, or Cold), AI reasoning, and the Status column pre-filled with New. The Switch node routes each lead through its matching output, but all three paths converge on the same Google Sheets node.

Only seeing one or two rows?

  • You must click Listen for test event before each curl request. The test listener times out after 120 seconds.
  • Confirm all three Switch outputs (Hot, Warm, Cold) have a connection line going to the Google Sheets node. If an output is disconnected, leads matching that tier will not be logged.
  • Check the execution log in n8n. Click each node to see if data flowed through it. If the Switch node shows output on one connector but not another, verify the tier value in your AI response matches the exact strings Hot, Warm, or Cold (case-sensitive).

Need help? Why are some of my leads not appearing in Google Sheets after the Switch node?

Your workflow now scores leads with AI, shapes the data into clean columns, routes by tier, and logs everything to a team-ready spreadsheet. Next up, you will wire the Hot output to a Slack alert so the sales team gets pinged the instant a high-value lead arrives.

Send Slack Alerts for Hot Leads

Your workflow now scores leads, routes them by tier, and logs every result to Google Sheets. That covers the data capture side perfectly.

A spreadsheet only helps if someone opens it. By sending an instant Slack notification when a Hot lead arrives, you ensure the sales team can respond within minutes instead of discovering the lead hours later during a manual sheet review.

In this step, get ready to:
  • Connect a Slack node to the Hot output of your Switch node.
  • Compose a formatted alert message using Slack markdown.
  • Test the full workflow end-to-end with Hot and Cold leads.
Add the Slack node to the Hot output

Your Switch node already has three outputs for Hot, Warm, and Cold leads. Right now all three connect to Google Sheets, but only Hot leads should also trigger a Slack alert.

  • In your n8n workflow editor, click the + button on the Hot output of your Switch node.
  • Search for Slack and select the Slack node.
  • In the Credential to connect with dropdown, select your saved Slack Access Token credential.
  • Set Resource to Message.
  • Set Operation to Send.
  • In the Channel field, select your #leads channel from the dropdown.

What does this node do?

The Slack node uses the chat.postMessage API method to send a message to your chosen channel whenever data flows through it.

Because you connected it to the Hot output specifically, only leads with a tier of "Hot" will trigger a Slack message. Warm and Cold leads flow through their own Switch outputs straight to Google Sheets without touching Slack.

Compose the formatted alert message

Slack supports a markdown-like syntax called mrkdwn for formatting messages. Asterisks create bold text and colons wrap emoji codes.

  • In the Slack node's Message field, paste the following formatted template:
*Hot Lead Alert* :fire:

*Name:* {{ $json.lead_name }}
*Company:* {{ $json.company }}
*Score:* {{ $json.score }}/100
*Industry:* {{ $json.industry }}

*AI Reasoning:* {{ $json.reasoning }}

*Suggested Action:* {{ $json.next_action }}

What does this message template do?

Each {{ $json.field_name }} expression pulls a value from the data flowing into the Slack node. These fields come from your Edit Fields (Set) node that you configured in the previous step.

The *text* syntax renders as bold in Slack. The :fire: renders as a fire emoji so the alert grabs attention in the channel.

  • Click Back to canvas to return to the workflow view.
  • Confirm the Slack node is connected to the Hot output of your Switch node alongside the Google Sheets connection.

Don't see the expressions resolving?

Make sure you toggled the Message field to expression mode (click the small gear or "Expression" toggle next to the field). If you paste the template in fixed-text mode, the {{ }} parts will be sent as literal text instead of pulling data.

Help me switch my Slack message field to expression mode

Test the full workflow end-to-end

Time to prove the entire pipeline works from webhook to Slack alert. You will send two test leads: one Hot and one Cold.

  • Click the Webhook node in your workflow, then click Listen for test event.
  • Open a terminal window and send a Hot lead by running this command:
curl -X POST [[WEBHOOK_URL="your n8n webhook test URL"]] -H "Content-Type: application/json" -d '{"name": "Dave Wilson", "company": "Wilson Steel Fabrication", "industry": "Manufacturing", "company_size": "50-200", "message": "Need urgent quote for bulk order of structural steel beams for new warehouse project. Timeline is 3 weeks.", "location": "Sydney, Australia"}'

Before you check the results, predict: which nodes in your workflow do you expect this lead to pass through?

The lead should flow through all five nodes: Webhook, Basic LLM Chain, Edit Fields, Switch (routed as Hot), then BOTH Google Sheets and Slack.

  • In the n8n editor, click on each node to confirm data passed through it successfully.
  • Switch to your Slack workspace and open the #leads channel.

You should see a formatted message with the fire emoji, Dave Wilson's name, company, score, industry, AI reasoning, and a suggested next action.

  • Open your Google Sheet and confirm a new row appeared for this lead with all columns populated.

Why check both Slack and the sheet?

Hot leads connect to both the Google Sheets node and the Slack node. Every lead gets logged regardless of tier. The Slack alert is an additional notification on top of the sheet entry.

Now test the Cold path to confirm it does NOT trigger Slack.

  • Click Listen for test event on the Webhook node again.
  • Send a Cold lead by running this command:
curl -X POST [[WEBHOOK_URL="your n8n webhook test URL"]] -H "Content-Type: application/json" -d '{"name": "Alex Student", "company": "University of Melbourne", "industry": "Education", "company_size": "1-10", "message": "Hi, I am a final year engineering student looking for career advice in the steel manufacturing industry. Can someone mentor me?", "location": "Melbourne, Australia"}'

Before you check: do you expect this lead to appear in Slack?

It should NOT appear in #leads. The Switch node routes it as Cold, which connects only to Google Sheets.

  • Confirm a new row appeared in your Google Sheet for Alex Student with a Cold tier.
  • Confirm your #leads channel has no new message for this lead.

Slack message not appearing for the Hot lead?

Check that the Slack node is connected to the Hot output of your Switch node (not Warm or Cold).

Confirm your bot has been invited to the #leads channel. Bots can only post to channels they have been added to.

Help me troubleshoot my Slack node not posting messages

  • Once both tests pass, click the Active toggle in the top-right corner of your workflow to publish it.

Your workflow is now live and will process any lead sent to the production webhook URL.

Secret mission

Daily Lead Digest

Your hot-lead alert handles urgency, but what about the big picture? Build a second workflow that posts a morning summary to Slack showing yesterday's lead volume and tier breakdown. The team gets a birds-eye view without ever opening the spreadsheet.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. The n8n Cloud free trial expires after 14 days with no charges. OpenAI costs are negligible (fractions of a cent per lead scored) but your pay-as-you-go balance remains active until you revoke the key.

Cost warning

If your Lead Scorer workflow stays published, anyone with your webhook URL can trigger executions that call the OpenAI API. Each call costs fractions of a cent, but an unexpected spike in requests could consume your balance. If you are stepping away, unpublish your workflows or revoke your OpenAI API key.

Resources you used:

  • n8n Cloud workflows (Lead Scorer and Daily Lead Digest).
  • OpenAI API key with pay-as-you-go balance.
  • Google Sheet "Lead Scores" in your Google Drive.
  • Slack app installed to your workspace.

Keep everything running

No action needed. Choose this if you are still actively building or want the webhook to keep scoring leads.

  • Your workflows will continue to process leads at the webhook URL as long as your n8n Cloud trial is active.
  • OpenAI charges fractions of a cent per scored lead.
  • Your Google Sheet will continue to accumulate rows.
  • The Slack app remains in your workspace and posts alerts whenever a Hot lead arrives.

Pause - I'll come back to this later

Shut down running workflows so no executions fire. Your credentials, sheet, and Slack app remain intact for when you return.

  • In n8n Cloud, open the Lead Scorer workflow.
  • Click the dropdown arrow next to the Publish button in the canvas header, then select Unpublish.
  • Repeat for the Daily Lead Digest workflow.
  • With both workflows unpublished, no webhook requests are processed and no scheduled triggers fire.
  • Your credentials, Google Sheet, and Slack app stay in place.

Delete - I don't want to use this again

Remove all project resources completely. Follow each step below.

  • Delete workflows in n8n Cloud: go to the Workflows list, click the three-dot menu next to the Lead Scorer workflow, and select Delete. Confirm deletion. Repeat for the Daily Lead Digest workflow.
  • Revoke your OpenAI API key: go to https://platform.openai.com/api-keys, find the key you created for this project, and click Delete. Confirm revocation.
  • Delete your Google Sheet: open Google Drive, right-click the "Lead Scores" spreadsheet, and select Move to trash.
  • Remove the Slack app from your workspace: in Slack on desktop, click your workspace name in the sidebar.
  • Select Tools & settings, then click Manage apps to open the Slack Marketplace.
  • From the left sidebar, select Installed apps.
  • Find and select your lead scorer app, then click App details.
  • Click the Configuration tab, scroll down, and select Remove app.

That's a Wrap!

That's a Wrap!

Nice work! You just built a production-ready AI lead scoring automation that takes raw inbound inquiries and turns them into scored, routed, team-ready data in seconds.

You've learned how to:

  • Built a webhook-triggered AI workflow that evaluates inbound leads against a B2B manufacturing ICP in real time using n8n and OpenAI.
  • Experienced the critical difference between freeform AI output and structured JSON output, and why enforcing schema is essential for downstream automation.
  • Implemented conditional routing that logs every scored lead to Google Sheets and sends instant Slack alerts for Hot leads so the sales team can respond in minutes.
  • Secret Mission: Built a scheduled daily digest workflow that posts a morning summary of lead volume and tier breakdown to Slack.

Ready to quiz yourself?