The Complete Playbook to Scrape ZoomInfo for High-Value B2B Leads
ZoomInfo holds a treasure trove of B2B data, but accessing it is a tough challenge. CAPTCHAs, browser fingerprinting, and strict IP bans are constant obstacles. Most scrapers can’t get past just a few requests.
That’s why this guide exists. We’ll walk you through how to bypass ZoomInfo’s defenses and extract clean, reliable data at scale — in 2025’s ever-evolving anti-bot landscape. Let’s dive in.
What Can You Actually Gather from ZoomInfo
ZoomInfo isn’t just a list. It’s rich business intelligence, broken down into four key buckets:
Company intelligence: Firmographics like company name, HQ, website, SIC/NAICS codes, revenue, employees, and corporate structure.
Contact info: Verified emails, direct phone numbers, job titles, departments, seniority levels, LinkedIn profiles.
Technology & operations: Insights into tech stacks, cloud providers, org charts, and reporting lines.
Business insights: Real-time updates on funding rounds, executive moves, intent signals, plus data confidence scores to help you filter quality leads.
How ZoomInfo Arranges Its Data
Most jump straight to parsing HTML. Rookie move. ZoomInfo hides its gold inside JSON blobs embedded in <script>
tags — clean, structured, and far easier to extract than fragile DOM elements.
Want to peek? Open your browser’s DevTools, check the Network tab filtered by “Doc,” and inspect the first HTML response. Look for a <script id="ng-state">
tag. That JSON contains everything — org charts, funding history, contacts, intent signals.
Extract that, and you’re miles ahead.
Why It’s Hard to Scrape ZoomInfo
ZoomInfo doesn’t play nice:
IP bans hit hard and fast. Too many requests? Bam — 429 “Too Many Requests” followed by 403 Forbidden and a banned IP.
CAPTCHAs pop up after just a few hits from the same IP — think “Press & Hold” puzzles designed to block bots.
Advanced fingerprinting spots even the slickest headless browsers by analyzing headers, JavaScript execution, Canvas/WebGL fingerprints, and more.
If you’re thinking “simple Requests script,” think again. You’ll get flagged immediately.
How to Overcome ZoomInfo’s Anti-Bot Protection
The secret? Your scraper must behave like a real human user. That means:
Stealth headless browsers: Use custom setups that mask automation signals and mimic human browsing.
Selenium with Undetected ChromeDriver or SeleniumBase
Puppeteer with the Puppeteer Stealth Plugin
Playwright with Playwright Stealth
These patch common giveaways like navigator.webdriver and spoof Canvas/WebGL fingerprints. But beware — they still consume lots of CPU and RAM at scale.
CAPTCHA-solving services: Integrate 2Captcha or Anti-Captcha to handle puzzles automatically. Yes, this adds cost and latency — but it’s non-negotiable if you want continuous scraping.
Rotating residential proxies: Never hammer ZoomInfo from a single IP. Residential proxies route through real consumer devices, making them nearly impossible for ZoomInfo to block. Rotate them on every request.
Use proxy pools with millions of IPs across hundreds of locations for consistent success.
Step-by-Step ZoomInfo Scraper Setup
1. Environment & dependencies
Create a clean Python environment, then install essentials:
python -m venv zoominfo-scraper
source zoominfo-scraper/bin/activate # Mac/Linux, or equivalent for Windows
pip install requests beautifulsoup4 urllib3
requests
: Fetch pages
BeautifulSoup
: Parse HTML
urllib3
: Handle proxy security warnings
2. Grab Hidden JSON with the Scraper
Here’s a Python class that:
Requests the ZoomInfo page with headers and proxies
Extracts the JSON from <script id="ng-state">
Saves the data to a file
import json
from typing import Optional, Any
import requests
from bs4 import BeautifulSoup
import urllib3
from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)
class ZoomInfoScraper:
def __init__(self, url: str) -> None:
self.url = url
self.headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Referer": url,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
}
self.proxies = self._setup_proxies()
def _setup_proxies(self) -> Optional[dict]:
username = "PROXY_USERNAME"
password = "PROXY_PASSWORD"
proxy_host = "gate.example.com:7000"
if not username or not password:
print("Proxy credentials not found. Running without proxies.")
return None
proxy_url = f"http://{username}:{password}@{proxy_host}"
return {"http": proxy_url, "https": proxy_url}
def fetch_html(self) -> str:
try:
response = requests.get(
self.url,
headers=self.headers,
proxies=self.proxies,
verify=False,
timeout=15,
)
response.raise_for_status()
return response.text
except requests.RequestException as e:
raise Exception(f"Request failed: {e}")
def extract_page_data(self, html: str) -> Optional[dict]:
soup = BeautifulSoup(html, "html.parser")
script = soup.find("script", {"id": "ng-state", "type": "application/json"})
if not script:
raise ValueError("Data script tag not found")
return json.loads(script.string).get("pageData")
def run(self) -> Optional[dict]:
print(f"Scraping {self.url.split('/')[-1]}...")
try:
html = self.fetch_html()
page_data = self.extract_page_data(html)
if page_data:
with open("page_data.json", "w") as f:
json.dump(page_data, f, indent=2)
print("Success - Data saved to page_data.json")
return page_data
print("No page data found")
except Exception as e:
print(f"Error: {e}")
return None
if __name__ == "__main__":
target_url = "https://www.zoominfo.com/c/anthropic-pbc/546195556"
scraper = ZoomInfoScraper(target_url)
scraper.run()
Run it. Boom. You get a JSON file packed with everything from employee counts to funding rounds and competitor lists.
How to Handle Scraping Thousands of Profiles
Method 1: Search Results Pagination
ZoomInfo search pages list companies filtered by industry, location, etc. For example, software companies in Germany.
The trick? Loop through the first 5 pages using the ?pageNum=
parameter. Extract company URLs, then feed those into your scraper.
Use libraries like tenacity
for retry logic and fake-useragent
to rotate your User-Agent headers — crucial to avoid detection.
pip install tenacity fake-useragent
Method 2: Competitor Crawling
Each company profile lists competitors. Use that data to crawl dynamically — uncovering new companies and expanding your dataset automatically.
Final Thoughts
Scraping ZoomInfo isn’t for the faint of heart—you need rotating residential proxies, stealthy headless browsers, CAPTCHA solvers, and smart retry and throttling logic. But once you get it right, you unlock a treasure trove of actionable B2B insights that fuel smarter marketing, sales, and competitive research.
To avoid the headaches, use tools that combine all these features out of the box—proxy rotation, CAPTCHA solving, stealth browsing, and retries—to get reliable data without the firefight.