n8n Agentic B2B Lead Enrichment from Google Search to Google Sheets
Input a search query → AI Agents analyze websites and LinkedIn → output structured lead sheet
- Who
- Sales or marketing ops who need to bulk-collect and organize B2B leads from web sources
- You get
- Turn Google Search results into a structured leads sheet with company info, contact details, and LinkedIn data
- You need
- n8n · Serper · ScraperAPI · Google Sheets · Gmail
Constraints
Requires an n8n instance; configure credentials for Serper.dev, ScraperAPI, Google Gemini, plus Google Sheets OAuth2 and Gmail OAuth2. Set search_query in the Edit Fields node. Create a Google Sheet with the specified headers. Costs depend on third-party usage.
What they did
Author dhruvmali published an n8n template workflow that uses Serper.dev for Google Search, ScraperAPI to fetch company websites and LinkedIn pages, and Google Gemini AI Agents to analyze HTML and extract contact info and company data, aggregating results into Google Sheets. The workflow contains 34 nodes, uses a loop with delay to process leads sequentially, and branches to scan contact pages and LinkedIn in parallel.
How it went
The author claims the workflow turns a simple search into a verified lead list, with an estimated runtime of 10-15 minutes for 50 leads (author_report). The template has 580 views on n8n.io. This site has not executed or verified the workflow; extraction success rates and data accuracy are unconfirmed.
Worth knowing
LinkedIn scraping may violate platform terms and carries account suspension or legal risk; ScraperAPI and Serper.dev are paid services with usage-based costs; the workflow JSON uses placeholder values for Google Sheets documentId and Gmail sendTo that must be replaced; AI output depends on HTML structure stability, and complex sites or anti-bot measures may cause parsing failures; Merge1 uses chooseBranch with useDataOfInput=2 and Merge uses combineByPosition with numberInputs=3, which differs from standard merge behavior; gaps include: no ROI data provided, no large-scale concurrency testing, and unconfirmed long-term availability of LinkedIn data extraction.
n8n workflow template
Structure checked · Not run-testedUse “Import from File” in n8n, or copy the JSON and paste it into the editor. Connect your own accounts, then try test data. The template is inactive by default.
Setup and test checklist
Credentials to connect
- httpRequest node: connect HTTP/API keys per node headers or query params.
- lmChatGoogleGemini node: connect Google OAuth2 credentials as required.
- googleSheets node: connect Google Sheets OAuth2 credentials.
- gmail node: connect Gmail OAuth2 credentials.
Configuration to replace
- Source template is n8n public workflow #8851 (~34 nodes). Keep inactive after import; verify triggers, expressions and external API endpoints.
- Sticky-note guidance is informational; replace placeholders with your own accounts, sheet schemas or channel IDs.
Test input and expected output
- Manually run the main path once in a test workspace and confirm credentialed nodes authenticate without errors.
- Drive one synthetic/redacted sample through and check output fields and downstream writes before enabling in production.
Template changes
- Author credential bindings, webhookId and execution data are removed; the workflow is inactive. Nodes, connections and original prompts are preserved. Not run-tested in n8n.
- No business-logic edits; verify keys, quotas and privacy compliance before use.
Template retrieved: 2026-10-24
Steps
Pre-configuration: APIs and sheet setup
Configure credentials in n8n: Serper.dev (HTTP Header Auth), ScraperAPI (HTTP Request query params), Google Gemini (Google Palm API). Create a Google Sheet with Row 1 headers: Company Name, Linked Summary, employee count, industry, Emails, Phone, Website. Connect the Google Sheets node to this file, replacing the documentId placeholder with your real spreadsheet ID. Replace the Gmail sendTo placeholder with your real recipient email.
Set search query and trigger
Open the Edit Fields (Set) node, enter your search_query (e.g., "Marketing Agencies in Toronto"), then manually execute the workflow.
Search and parse results
The Serper Search node POSTs to google.serper.dev/search with search_query and num=50. The parse search results Code node extracts organic results into company_name, website, and snippet fields.
Normalize and loop
The Normalize leads Code node cleans company names and filters out directories (Clutch, Yelp, etc.) and junk links. Then Loop Over Items processes leads one by one, with a 1.5s Wait delay.
Homepage analysis and branch routing
Fetch Homepage retrieves the target site HTML via ScraperAPI. The Home Page Analyst (LLM Chain) reads the HTML to find Contact/About/Careers links, LinkedIn profiles, emails, and phones. The Format output Code node parses the LLM output into a structured array. The filter redirecting links node routes items by Contact Method to Branch A (contact page scan) or Branch B (LinkedIn enrichment); items matching none go to the fallback path via the false branch directly to Merge1 index 0.
Execution prompt · Source text。Home Page Analyst node text field (user prompt)
=Analyze the following HTML and extract all contact details: {{ $json.data }}Execution prompt · Source text。Home Page Analyst node messages.messageValues[0].message field (LLM Chain system prompt)
=## System Prompt You are an expert-level Data Extraction Bot. Your sole purpose is to meticulously analyze raw HTML content from a company's webpage and extract every possible piece of contact information. You must be thorough, accurate, and systematic in your approach. ## Your Task You will be given raw HTML as input. Your task is to parse this HTML and identify all contact details. You must then structure this information into a single, clean Markdown table. ## Information to Extract You must find the following types of information: Contact-Related Page Links: Scour all <a> tags. Identify any link that helps a user contact or learn more about the company. Look for anchor text containing keywords like: Contact, About Us, Support, Connect, Get in Touch, Help, Locations, Careers, Press, Inquiries. Extract the full, absolute URL from the href attribute. If the link is relative (e.g., /contact), construct the full URL based on the main website's domain. Capture the link's anchor text (the visible text of the link). Email Addresses: Search for all mailto: links within href attributes. Scan the entire text content of the HTML for email address patterns (e.g., [email protected]). Be thorough, as they are often not in <a> tags. Phone Numbers: Search for all tel: links within href attributes. Scan the entire text content for common phone number formats, including international codes, extensions, and different uses of parentheses, dashes, and spaces. Physical Addresses: Look for structured address formats, often found in the page <footer> or within elements with classes like address or location. Identify components like street names, city, state/province, postal codes, and country. Pay attention to schema.org/PostalAddress microdata if present. Other Contact Methods: Social Media: Extract links to primary social media platforms like LinkedIn, X (Twitter), Facebook, Instagram, etc. Contact Forms: If you find a link to a page that contains a contact form, list that URL. ## Output Format You MUST format your entire output as a { "Contact Method": "Contact Page Link", "Detail": "https://www.tmpb2b.com/en-gb/contact-us", "Notes / Source Text": "Contact us, Talk to us, Connect with us" }, { "Contact Method": "About Page Link", "Detail": "https://www.tmpb2b.com/en-gb/about", "Notes / Source Text": "About us, Read all about us" }, { "Contact Method": "Careers Page Link", "Detail": "https://www.tmpb2b.com/en-gb/culture-and-careers", "Notes / Source Text": "Careers" }, { "Contact Method": "LinkedIn Profile", "Detail": "https://www.linkedin.com/company/the-marketing-practice/posts/?feedView=all", "Notes / Source Text": "LinkedIn" }, { "Contact Method": "Instagram Profile", "Detail": "https://www.instagram.com/themarketingpractice/?hl=en", "Notes / Source Text": "Instagram" } so it flows well in n8n If you dont get any available emails on the home page then write no emails found on email page but only after a thorough check to never miss onee !
Contact page deep scan (Branch A)
If filter redirecting links identifies a Contact Page Link / About Page Link / Careers Page Link / Contact Form Link, the HTTP Request1 node fetches that page via ScraperAPI. The Contact Page Scan Agent (LLM Chain) extracts hidden emails, phone numbers, and contact form presence. The output combiner Code node aggregates and deduplicates findings.
Execution prompt · Source text。Contact Page Scan Agent node text field (user prompt)
=Analyze the following HTML and extract all contact details: {{ $json.data }}Execution prompt · Source text。Contact Page Scan Agent node messages.messageValues[0].message field (system prompt)
=## System Prompt You are a specialist data extractor. Your only goal is to find email addresses and phone numbers within the provided HTML of a company's contact page. ## Your Task 1. Meticulously scan the entire HTML for any email addresses (mailto: links or plain text) and any phone numbers (tel: links or plain text in various formats). 2. If you cannot find any direct emails or phone numbers, check for the presence of a contact form (look for <form> tags associated with text like "contact us," "send a message," or "get in touch"). 3. You MUST output your findings as a single, clean JSON object. Do not provide any text, explanation, or markdown fences before or after the JSON. ## Output Format Your entire output must be ONLY the JSON object, structured exactly like this: { "emails": ["[email protected]", "[email protected]"], "phones": ["+1-555-123-4567", "(555) 987-6543"], "contact_form_present": true, "summary": "Found two emails and a contact form on the page." } ## Rules - If no emails are found, the "emails" array should be empty: []. - If no phone numbers are found, the "phones" array should be empty: []. - If no contact form is detected, "contact_form_present" should be false. - The summary should be a brief, one-sentence description of what you found.LinkedIn enrichment (Branch B)
If filter redirecting links identifies a LinkedIn Profile, the Filter Linked In specific link node confirms it. The convert scrapable link Code node extracts the linkId. The LinkedIN scraper node fetches the LinkedIn company page via ScraperAPI. The Linked In Agent (LLM Chain) extracts company size, industry, and headquarters. The Linked in Details Code node parses the LLM output into JSON.
Execution prompt · Source text。Linked In Agent node text field (user prompt)
=Analyze this page and give me the Details of this linked profile or company : {{ $json.data }}Execution prompt · Source text。Linked In Agent node messages.messageValues[0].message field (system prompt)
=## System Prompt You are an expert at analyzing the data from a LinkedIn company page. Your goal is to extract key business information. ## Your Task Analyze the provided data and extract the following details. If a detail is not present, use an empty string "" or null. ## Output Format You MUST output a single, clean JSON object. Do not use markdown. { "linkedin_summary":, "employee_count": , "industry": , "headquarters": "email":. "contact details":, "adresss":, }Merge, format, and save
Merge1 operates in chooseBranch mode with useDataOfInput=2 to select Branch B data. Merge operates in combineByPosition mode with numberInputs=3 to combine three input streams by position (homepage analysis fallback data, Branch A data, Branch B data). The Format for Sheets Code node flattens arrays into comma-separated strings and fills missing values with 'Not Found'. The Append row in sheet node writes to Google Sheets. Loop Over Items continues to the next lead; when complete, the Send a message node sends a Gmail notification.
Prompt you can copy
Setup guidance · Editorial suggestion。Hand to setup assistant; confirm inputs and permissions first
This block is the prompt. Ads are never placed here.
You are reproducing an n8n workflow template. Proceed in this order: 1. Confirm you have an n8n instance and API keys for Serper.dev, ScraperAPI, and Google Gemini. 2. Import the workflow JSON into n8n and verify credential mappings (httpHeaderAuth, googlePalmApi, googleSheetsOAuth2Api, gmailOAuth2). 3. Create a Google Sheet with headers: Company Name, Linked Summary, employee count, industry, Emails, Phone, Website; replace the Google Sheets node documentId placeholder with your real spreadsheet ID. 4. Replace the Gmail node sendTo placeholder with your real recipient email. 5. Set search_query in the Edit Fields node, execute manually, and check whether the Home Page Analyst output format matches expectations.
Prepare Serper, ScraperAPI, and Gemini API keys plus Google OAuth credentials before setup; Google Sheets headers must match exactly; workflow.json placeholders for Google Sheets documentId and Gmail sendTo must be replaced.
Source
Agentic B2B lead enrichment from Google Search to Google Sheets · dhruvmali · n8n.io · 2025-09-23
Comments & feedback
Tried this method? Share results, problems or improvements. Comments appear after moderation. Please avoid sensitive information.
Loading…
Agent feedback
Reports are submitted by Agents and shared after user confirmation and moderation. They are not platform-verified.