Google Sheets + LinkedIn, clean lead lists on demand
Lead sourcing sounds simple until you’re ten tabs deep, copying names into a sheet, and realizing half the profiles are duplicates or not even the right role.
This LinkedIn leads automation hits sales leads and recruiters first, but founders doing their own outreach feel it too. You end up spending your best hours doing the most mechanical work.
This workflow turns three inputs (position, industry, region) into a clean, deduped Google Sheet of LinkedIn profiles, complete with context so you know why each person showed up.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Google Sheets + LinkedIn, clean lead lists on demand
flowchart LR
subgraph sg0["On form submission Flow"]
direction LR
n0["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>HTTP Request"]
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/form.svg' width='40' height='40' /></div><br/>On form submission"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Code in JavaScript"]
n3@{ icon: "mdi:cog", form: "rounded", label: "Wait", pos: "b", h: 48 }
n4["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Code in JavaScript1"]
n5@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields", pos: "b", h: 48 }
n6@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Pagination Check", pos: "b", h: 48 }
n7@{ icon: "mdi:database", form: "rounded", label: "Append or update row in sheet", pos: "b", h: 48 }
n8@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields1", pos: "b", h: 48 }
n3 --> n7
n5 --> n0
n8 --> n4
n0 --> n2
n6 --> n0
n2 --> n3
n1 --> n5
n4 --> n6
n7 --> n8
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n1 trigger
class n6 decision
class n7 database
class n0 api
class n2,n4 code
classDef customIcon fill:none,stroke:none
class n0,n1,n2,n4 customIcon
The Problem: LinkedIn research turns into copy-paste chaos
If you’ve ever tried building a targeted list of LinkedIn profiles manually, you know the real cost isn’t “finding people.” It’s everything around it. You search, open profiles, copy a name, paste it into Sheets, grab a title, then realize the formatting is inconsistent. “Head of Growth” becomes “Head, Growth | B2B SaaS” and now your filtering is broken. Add two people on your team doing the same research and you get duplicates, missing links, and a sheet that nobody trusts.
The friction compounds. Here’s where it usually breaks down.
- Manual list-building often eats about 2–3 hours per week, and that’s for a small campaign.
- People paste different columns in different orders, so your “master sheet” becomes a junk drawer.
- Duplicates slip in fast, which means outreach gets sloppy and sometimes embarrassing.
- You lose the search context, so later you can’t remember which role/region query produced each lead.
The Solution: Google-powered LinkedIn profile lists that land cleanly in Sheets
This workflow starts with a simple web form. You enter a target position, industry, and region, then submit. n8n takes those inputs and runs a Google Custom Search query that’s restricted to LinkedIn profile URLs, so you’re not wading through random results. Each search page is processed to extract usable fields like the person’s name, a cleaned job title, the LinkedIn link, a short description snippet, and an image URL. Then the workflow appends or updates rows in your Google Sheet, keeping columns consistent and removing duplicates as it goes. If there are more results available, it automatically paginates and repeats until it hits the limit.
The workflow begins when you submit the form. It queries Google, parses the results into structured lead rows, waits briefly between requests, then writes everything into Google Sheets while tracking pagination state. When there’s nothing left to fetch, it stops on its own.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you need 80 LinkedIn profiles for “VP Marketing” in “B2B SaaS” in “New York.” Manually, it’s easy to spend about 2 minutes per lead to open, sanity-check, and paste fields, plus another 30 minutes cleaning duplicates and columns, so you’re around 3 hours. With this workflow, you spend maybe 2 minutes submitting the form, then wait roughly 5–10 minutes for Google results to process and land in Sheets. The list is ready to use, with the original search context included.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store and dedupe lead rows.
- Google Custom Search to find LinkedIn profiles via Google.
- Google Custom Search API key (get it from Google Cloud Console)
Skill level: Intermediate. You’ll paste an API key, connect Google Sheets OAuth2, and confirm your sheet columns match what the workflow writes.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
You submit a short form. The trigger is an n8n web form where you enter position, industry, and region. That keeps list-building consistent across your team, because everyone starts from the same three inputs.
Paging is initialized upfront. The workflow sets starting values for pagination, so it can fetch more than one page of results without you babysitting it.
Google Custom Search is queried for LinkedIn profiles. An HTTP request sends your search to Google with a restriction to LinkedIn profile URLs. A processing step then extracts the fields you actually care about, and cleans job titles with custom logic so your sheet stays filterable.
Results land in Google Sheets, then the workflow decides if it should continue. After a short wait (helpful for rate limits), each profile is appended or updated in your sheet. Pagination fields are mapped and evaluated; if more results exist, the workflow loops and fetches the next batch.
You can easily modify the search query structure to target niche roles, or swap the output to another destination (like a CRM) based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Form Trigger
Set up the form that initiates the workflow and collects the search inputs used in the external query.
- Add the Form Submission Trigger node and open its settings.
- Set Form Title to
form. - Set Form Description to
add details like position, industry, place. - Add three required fields with labels
postion,industry, andregion, and placeholdersposition,industry, andregionrespectively. - Confirm the trigger connects to Initialize Paging Values as the next node in the flow.
postion because it is referenced in expressions later in the workflow.Step 2: Connect Google Sheets
Configure the spreadsheet destination for the processed profile data.
- Add the Update Spreadsheet Records node.
- Credential Required: Connect your
googleSheetsOAuth2Apicredentials. - Set Operation to
appendOrUpdate. - Select the document with Document set to
[YOUR_ID]and the sheet Sheet Name set toSheet1(gid=0). - Map columns using the existing expressions: name →
{{ $json.name }}, img link →{{ $json.image }}, position →{{ $json.title }}, description →{{ $json.snippet }}, profile links →{{ $json.link }}, searched region →{{ $('Form Submission Trigger').item.json.region }}, searched industry →{{ $('Form Submission Trigger').item.json.industry }}, searched position →{{ $('Form Submission Trigger').item.json.postion }}.
[YOUR_ID] with your actual Google Sheet ID before testing, or the append/update action will fail.Step 3: Set Up the External Search Request
Build the Google Custom Search request using the form inputs and initial pagination values.
- Open Initialize Paging Values and add two assignments: currentStartIndex as
1and maxPages as10. - Open External Search Request and set URL to
https://www.googleapis.com/customsearch/v1. - Credential Required: Connect your
httpBasicAuthcredentials. - Enable Send Query and set the query parameters: cx to
[YOUR_ID], q to{{ $('Form Submission Trigger').item.json.postion }} {{ $('Form Submission Trigger').item.json.industry }} {{ $('Form Submission Trigger').item.json.region }} site:linkedin.com/in, and start to{{ $runIndex == 0 ? $json.currentStartIndex : $node["Pagination Continuation Check"].json.startIndex }}.
cx parameter must be your Google Custom Search Engine ID, not your API key.Step 4: Set Up Processing, Delay, and Pagination Loop
Process search results, throttle requests, write to the sheet, and loop through additional pages if available.
- Verify Search Result Processor contains the provided JavaScript to extract
name,title,link,snippet,image, and pagination flags. - Set Pause Interval to wait Amount
3to avoid API throttling between requests. - In Map Pagination Fields, enable Include Other Fields and map startIndex to
{{ $('Search Result Processor').item.json.startIndex }}and hasMoreResults to{{ $('Search Result Processor').item.json.hasMoreResults }}. - Confirm Pagination State Builder contains the provided JavaScript that outputs
continueLoopandstartIndex. - In Pagination Continuation Check, set the boolean condition to
{{ $json.continueLoop }}equalstrueto loop back to External Search Request when more results exist.
Step 5: Test and Activate Your Workflow
Run a manual test to verify data flow and then activate the automation for ongoing use.
- Click Execute Workflow and submit the form with sample values for
postion,industry, andregion. - Confirm External Search Request returns results and Search Result Processor outputs structured fields.
- Verify that rows are appended/updated in the target sheet by Update Spreadsheet Records.
- Check the loop behavior by verifying Pagination Continuation Check continues until
hasMoreResultsbecomes false. - When successful, switch the workflow to Active to enable production use.
Common Gotchas
- Google Sheets credentials can expire or need specific permissions. If things break, check the Google connection in n8n’s Credentials section first, then confirm the sheet is shared with the same Google account.
- If you’re using Wait nodes or external requests, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses, especially when Google returns results slowly.
- Google Custom Search can return odd snippets, and title cleanup rules might not match your niche. If the “cleaned job title” looks off, tweak the logic in the Search Result Processor step so you’re not fixing titles by hand later.
Frequently Asked Questions
About 30 minutes once your Google API key and sheet are ready.
No. You’ll connect accounts, paste your API key, and point the workflow at the right Google Sheet.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in Google Custom Search API usage costs, which are usually a few dollars as volume grows.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and you should, honestly. You can tweak the query inside the External Search Request node to include extra keywords (like “fintech” or “Series B”) or exclude terms that attract irrelevant profiles. Many teams also add a simple filter after Search Result Processor to drop results that don’t match the region or role phrasing they expect. If you want enrichment, route each profile link to tools like Hunter.io, Clearbit, or People Data before writing the final row.
Usually it’s expired OAuth or the sheet permissions changed. Reconnect Google Sheets in n8n, then confirm the spreadsheet and target tab still exist and the “Append or update row” step points to the right one. If the sheet columns were renamed, the workflow can fail silently or write to the wrong fields, so double-check headers match the required columns (name, title, profile link, description, image link, searched position, searched industry, searched region).
On n8n Cloud, the practical limit is your monthly executions and how many pages you let it fetch per run; most small teams comfortably pull a few hundred leads per week. If you self-host, there’s no execution cap, so it mostly comes down to your server and Google Custom Search quota.
Sometimes. Zapier and Make are great for simple “new row → send email” flows, but this workflow needs looping, pagination state, and conditional checks, and that tends to get expensive or awkward on simpler builders. n8n handles branching and code-based cleanup in one place, which is why the output sheet stays consistent. The tradeoff is a little more setup responsibility. If you want someone to sanity-check your version, Talk to an automation expert.
Once this is running, lead research stops being a weekly cleanup project. Your sheet stays tidy, your outreach moves faster, and you can finally trust the list you’re working from.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.