Serper + Google Sheets: enriched leads, zero rework
Your lead sheet starts simple. Then it turns into a mess: missing headcount, “N/A” revenue, random LinkedIn URLs, and the same company showing up twice under slightly different names.
Serper lead enrichment hits sales ops and demand gen teams first, because they’re the ones cleaning lists right before outreach. But founders doing scrappy outbound and consultants building prospect databases feel it too. You want a sheet you can trust, not a spreadsheet you have to babysit.
This n8n workflow takes raw domains from Google Sheets, finds the right ZoomInfo company page via Serper, pulls structured firmographics through an Oxylabs proxy, and writes clean fields back to your sheet. You’ll see how it works, what you need, and what to watch out for.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Serper + Google Sheets: enriched leads, zero rework
flowchart LR
subgraph sg0["Manual Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Manual Trigger", pos: "b", h: 48 }
n1@{ icon: "mdi:database", form: "rounded", label: "Load Unprocessed Domains", pos: "b", h: 48 }
n2@{ icon: "mdi:swap-vertical", form: "rounded", label: "Process Each Domain", pos: "b", h: 48 }
n3["<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/>Search ZoomInfo via Serper"]
n4@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Check Search Results Found", pos: "b", h: 48 }
n5["<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/>Extract Domain and ZoomInfo .."]
n6@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Validate if Domain Matches", pos: "b", h: 48 }
n7["<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/>Scrape ZoomInfo Page"]
n8["<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/html.dark.svg' width='40' height='40' /></div><br/>Extract Company Data"]
n9["<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/>Parse JSON Company Info"]
n10@{ icon: "mdi:database", form: "rounded", label: "Save Company Details", pos: "b", h: 48 }
n11@{ icon: "mdi:database", form: "rounded", label: "Mark Domain as Processed", pos: "b", h: 48 }
n12@{ icon: "mdi:cog", form: "rounded", label: "Rate Limit Delay", pos: "b", h: 48 }
n13@{ icon: "mdi:cog", form: "rounded", label: "Processing Delay", pos: "b", h: 48 }
n0 --> n1
n13 --> n11
n12 --> n10
n2 --> n3
n8 --> n9
n10 --> n2
n7 --> n8
n9 --> n12
n1 --> n2
n11 --> n2
n4 --> n5
n4 --> n13
n3 --> n4
n6 --> n7
n6 --> n2
n5 --> n6
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 n0 trigger
class n4,n6 decision
class n1,n10,n11 database
class n3,n7 api
class n5,n9 code
classDef customIcon fill:none,stroke:none
class n3,n5,n7,n8,n9 customIcon
The Problem: Lead enrichment creates rework (and bad targeting)
Enriching a list of company domains sounds like a quick task until you do it at scale. You search each domain, open three tabs, guess which result is the “official” profile, then copy bits into a Google Sheet that slowly becomes inconsistent. Someone on the team “fixes” a company name, another person pastes a LinkedIn link from a different entity, and now your CRM import creates duplicates. The worst part is the timing: you usually discover the gaps right before outreach, when you needed clean segmentation yesterday.
The friction compounds. Here’s where it breaks down.
- Manual research turns into about 10 minutes per company once you include checking sources and formatting the sheet.
- You end up with mismatched companies because search results look right at a glance, then fail later during personalization.
- Duplicates creep in when two people enrich the same domain on different days and label it slightly differently.
- Your “target accounts” list becomes guesswork, so headcount and revenue-based targeting never really sticks.
The Solution: Enrich domains in Sheets using Serper + ZoomInfo scraping
This workflow treats your Google Sheet like a queue. It looks for rows where the domain exists but the “processed” flag is empty or false, then enriches those rows in batches. For each domain, it uses Serper to search ZoomInfo with a targeted query, validates the result so you don’t write junk URLs, and then fetches the ZoomInfo company page through Oxylabs to avoid the usual scraping blocks. Next, it extracts structured business fields (company name, address, industry, revenue, employee count, LinkedIn URL, and more). Finally, it writes everything back into the right columns and marks the row as processed, which keeps the workflow from looping over the same companies again.
The workflow starts from a manual run (or a schedule if you swap the trigger). It then loops through unprocessed domains, enriches them one-by-one with rate limiting, and merges the extracted fields back into a single update. Your Google Sheet ends up as a clean, ready-to-use dataset for outreach, segmentation, or CRM imports.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you have 120 domains in a Google Sheet from a webinar sponsor list. Manually, even a “quick” pass at about 10 minutes per domain is roughly 20 hours, and it still leaves gaps when you get interrupted. With this workflow, you run it once, let it process in batches with built-in waiting, and check the sheet later. Realistically, your active time becomes about 10 minutes to prep the sheet and spot-check a few rows, while the enrichment runs in the background.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store domains and enriched outputs
- Serper API for reliable ZoomInfo search matching
- Oxylabs credentials (get them from your Oxylabs dashboard)
Skill level: Intermediate. You’ll connect accounts, paste API keys, and map a few columns in Google Sheets nodes.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
It starts with a list in Google Sheets. The workflow finds rows where you have a domain but the processed column is blank or false, so it only touches what’s new.
Search results get validated before scraping. Serper runs a ZoomInfo-focused query for each domain, and an If check filters out weak matches so you don’t pollute your sheet with the wrong company profile.
The workflow scrapes the company page safely. It requests the ZoomInfo page through Oxylabs (a proxy layer), then extracts structured fields like company name, address, industry, revenue, employee count, and LinkedIn URL.
Your sheet gets updated and locked in. A final Google Sheets update writes the new values and marks the row as processed, which means you can rerun it anytime without creating duplicates.
You can easily modify the search query to focus on a different country, or adjust the columns you write back to Google Sheets based on your needs. See the full implementation guide below for customization options.
Common Gotchas
- Google Sheets OAuth credentials can expire or lose access when the sheet owner changes. If things break, check the n8n Google Sheets credential and the file sharing permissions in Google Drive first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Serper and Oxylabs keys can be valid but still fail due to rate limits or blocked endpoints. If you start seeing inconsistent results, lower the batch size and add more delay between requests.
Frequently Asked Questions
About 45 minutes if you already have your API keys and the Google Sheet ready.
No. You’ll mostly connect accounts and paste credentials into a couple of HTTP Request nodes.
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 Serper credits and an Oxylabs subscription for scraping.
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 it’s one of the first tweaks people make. Update the Serper search query text so it targets your preferred geography (the default is set up for a Czech Republic focus). You can also change which fields you extract and write back by adjusting the Google Sheets column mapping. If you want it fully hands-off, swap the Manual Trigger for a Schedule Trigger so it runs daily or weekly.
Usually it’s OAuth access expiring or the sheet permissions changing. Reconnect the Google Sheets credential inside n8n, then confirm the Google Sheet is still shared with the right Google account. Also check that you updated the spreadsheet ID in every Sheets node, not just the first one.
A few hundred at a time is normal, but the real limit is your Serper credits, Oxylabs plan, and how aggressively you rate-limit requests.
Often, yes, because this workflow isn’t just “move data from A to B.” You’re doing batch processing, conditional validation, and multi-step scraping, which tends to get expensive or awkward in Zapier. n8n also gives you a self-hosted path when you need lots of runs without watching task limits. That said, if you only need a simple 2-step enrichment with a single API call, Zapier or Make can be faster to set up. The decision usually comes down to volume and how much control you want over error handling. Talk to an automation expert if you want a quick recommendation for your exact stack.
Once your enrichment runs like a background job, your sheet stops being a liability. You get cleaner targeting, fewer duplicates, and a prospect list you can actually build on.
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.