Apollo.io hands you 10,000 free email credits a month, then limits how many of those contacts you can actually take out of the platform. Free accounts get 120 exports per year. Paid plans start at $49/month. For an agency pulling a few thousand leads, the credits are the cheap part; the export ceiling is what stops the work.
A free Apollo lead scraper closes that gap by reading the search results your browser already renders and writing them to CSV. Built with Python and Selenium, you control the fields, the pagination, the pacing, and where the data lands, with no subscription tier standing between you and your own search results.
One tradeoff is worth understanding before you write any code: anything that drives your logged-in Apollo session, whether a Chrome extension or your own script, is exporting past the plan cap using your account. Sessions that pull too hard get flagged, and a flagged seat costs more than the export credits you saved. That's why the proxy rotation, rate limiting, and randomized delays later in this guide matter as much as the parsing logic.
Two routes skip your account entirely. Apify actors such as coladeu/apollo-people-leads-scraper extract structured Apollo people data with no Apollo account, cookies, or authentication, from $3.00 per 1,000 results, though they exclude emails and phone numbers. Licensed third-party Data APIs sell Apollo-style people and company records on a free tier that shifts to metered pricing, with no session to ban. If your volume is high and your Apollo seat is business-critical, price those out before committing to Selenium.
Best for: Agencies, founders, and recruiters who need more Apollo rows than their plan releases
Stack: Python, Selenium, rotating proxies
Cost: Free apart from proxy spend
Main risk: Account flagging when requests come too fast or too regularly
What an Apollo lead scraper does, and why build your own
An Apollo lead scraper automates extraction from Apollo.io: it walks search results, contact profiles, and company pages the way a person would, then writes the rows to a file. A free Apollo lead scraper you build yourself collects names, job titles, verified work emails, phone numbers, LinkedIn URLs, company size, industry, and location across thousands of records in the time it takes to copy a few dozen by hand.
People build one because of the export meter. Apollo prices by export volume, and the Basic plan ($49/month) caps you at 900 contacts a month. Free accounts hit tighter walls: a per-export record cap and a limit on how deep you can page through results. The Chrome extensions competing for this search advertise exactly that fix, getting past the 25-record export limit and the 5-page browsing limit on free accounts. Running into those caps in the middle of a campaign is what sends most people looking for a scraper.
The arithmetic is simple. A $50/month Apollo subscription buys 10,800 exports a year. A scraper you run yourself has no row cap at all, and your costs are proxies ($10–30/month) plus whatever compute you point at it, under half the subscription price for unlimited volume.
Three routes to the same data
- Browser extensions. They drive your own logged-in Apollo session and export past the plan cap. Free, installed in a minute, and the account doing the exporting is yours, which is where the risk sits.
- A scraper you write. The route this guide covers. You control pacing, which fields you keep, and the output format, and nothing routes through a third party's server. You also own the maintenance when Apollo changes its markup.
- Licensed data APIs and pay-per-result actors. Apollo-style people and company data delivered over an API, commonly a free tier followed by metered pricing. Some hosted actors pull structured Apollo people data with no account, no cookies, and no login, at around $3 per 1,000 results, though those runs exclude emails and phone numbers.
Account risk is the tradeoff that decides between them. Anything driving your logged-in session, extension or automation script alike, exports under your seat, and a session pushing thousands of rows past its plan cap is the pattern that gets accounts flagged. Writing your own scraper lets you throttle to human pace, randomize delays between pages, and rotate proxies, which lowers the exposure. Routes that never touch an Apollo login remove it entirely, since there is no account to ban, at the cost of the contact fields Apollo keeps behind authentication.
Maintenance is the second tradeoff. Selector-based scrapers break the moment Apollo ships new markup, which is why element not found is the failure you are most likely to debug later in this guide. Some commercial tools now read the visible fields on the page with AI instead of fixed CSS selectors and can rerun a saved search on a schedule, which survives layout changes better than hardcoded paths. Building your own means taking that job on; keeping every selector in a single config block turns the fix into a two-minute edit rather than a rewrite.
Build your own when: you need volume Apollo's plans do not sell, you want the raw data to stay on your machine, and you can absorb an occasional afternoon of selector repair.
Pay for access instead when: the Apollo seat is business critical, you need verified emails and direct dials at volume, or nobody on the team owns the maintenance.
Method 1: Building a Python Apollo Scraper
You'll automate the full workflow from search to export.
Prerequisites and Setup
Install Python 3.8+ and required libraries:
pip install selenium pandas openpyxl webdriver-manager --break-system-packages
You'll also need Chrome or Firefox browser installed.
Step 1: Initialize Your Selenium WebDriver
Create a new file called apollo_scraper.py:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import time
import pandas as pd
import random
class ApolloScraper:
def __init__(self, email, password):
self.email = email
self.password = password
self.driver = self.setup_driver()
def setup_driver(self):
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64)')
driver = webdriver.Chrome(options=options)
return driver
The disable-blink-features argument hides Selenium's automation signature. Apollo's anti-bot detection looks for this flag.
Random user agents make your scraper appear as a normal browser.
Step 2: Automate Apollo Login
Add this login method to your class:
def login(self):
self.driver.get('https://app.apollo.io/#/login')
time.sleep(3)
email_field = self.driver.find_element(By.NAME, 'email')
password_field = self.driver.find_element(By.NAME, 'password')
email_field.send_keys(self.email)
password_field.send_keys(self.password)
login_button = self.driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]')
login_button.click()
time.sleep(5)
print("Logged in successfully")
This navigates to Apollo's login page, fills credentials, and clicks submit.
The 5-second delay after login prevents triggering rate limits immediately.
Step 3: Navigate to Your Saved List
def navigate_to_list(self, list_url):
self.driver.get(list_url)
time.sleep(4)
# Wait for contacts to load
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'zp_contact_row'))
)
print("List loaded successfully")
Replace list_url with your actual Apollo saved list URL.
The WebDriverWait ensures the page fully loads before scraping begins.
Step 4: Extract Contact Data
The extraction loop:
def scrape_contacts(self):
contacts = []
# Find all contact rows
rows = self.driver.find_elements(By.CLASS_NAME, 'zp_contact_row')
for row in rows:
try:
# Extract name
name = row.find_element(By.CLASS_NAME, 'zp_contact_name').text
# Extract title
title = row.find_element(By.CLASS_NAME, 'zp_contact_title').text
# Extract company
company = row.find_element(By.CLASS_NAME, 'zp_company_name').text
# Extract email (if available)
try:
email = row.find_element(By.CLASS_NAME, 'zp_contact_email').text
except:
email = "Not available"
# Extract location
try:
location = row.find_element(By.CLASS_NAME, 'zp_contact_location').text
except:
location = "Not available"
contacts.append({
'name': name,
'title': title,
'company': company,
'email': email,
'location': location
})
except Exception as e:
print(f"Error extracting contact: {e}")
continue
return contacts
This loops through each visible contact row and extracts key fields.
The try-except blocks handle missing data gracefully. Not every contact has email or phone visible.
Step 5: Handle Pagination
Apollo limits page views to 25 contacts. You need pagination logic:
def scrape_all_pages(self, max_pages=10):
all_contacts = []
for page in range(max_pages):
print(f"Scraping page {page + 1}")
# Scrape current page
contacts = self.scrape_contacts()
all_contacts.extend(contacts)
# Random delay between pages (2-5 seconds)
delay = random.uniform(2, 5)
time.sleep(delay)
# Click next page button
try:
next_button = self.driver.find_element(By.CSS_SELECTOR, 'button[aria-label="Next page"]')
next_button.click()
time.sleep(3)
except:
print("No more pages available")
break
return all_contacts
Random delays between pages mimic human behavior. Consistent timing triggers bot detection.
The max_pages parameter prevents infinite loops if pagination breaks.
Step 6: Export to CSV
def export_to_csv(self, contacts, filename='apollo_leads.csv'):
df = pd.DataFrame(contacts)
df.to_csv(filename, index=False)
print(f"Exported {len(contacts)} contacts to {filename}")
Pandas converts your contact list into a clean CSV file.
You can also export to Excel by changing the file extension to .xlsx.
Complete Usage Example
# Initialize scraper
scraper = ApolloScraper(
email='[email protected]',
password='your-password'
)
# Login
scraper.login()
# Navigate to saved list
list_url = 'https://app.apollo.io/#/people?savedListId=YOUR_LIST_ID'
scraper.navigate_to_list(list_url)
# Scrape 10 pages (250 contacts)
contacts = scraper.scrape_all_pages(max_pages=10)
# Export results
scraper.export_to_csv(contacts)
# Cleanup
scraper.driver.quit()
This workflow logs in, scrapes your target list, and exports everything to CSV.
For 1,000 contacts, set max_pages=40 (1,000 / 25 per page).
Rate Limiting and Avoiding Account Bans
Apollo monitors scraping patterns. Follow these rules to stay under the radar:
Limit daily volume: Scrape no more than 1,000 contacts per day. Spread this across 8-10 hours.
Randomize delays: Use random.uniform(2, 10) for delays between actions. Never use fixed intervals.
Rotate user agents: Change browser fingerprints every session:
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
options.add_argument(f'--user-agent={random.choice(user_agents)}')
Use residential proxies: Datacenter IPs get flagged instantly. Services like BrightData or Smartproxy cost $10-30/month but keep your scraper alive.
Add proxy support to your driver setup:
def setup_driver_with_proxy(self, proxy):
options = webdriver.ChromeOptions()
options.add_argument(f'--proxy-server={proxy}')
return webdriver.Chrome(options=options)
Cost Comparison: Custom Scraper vs Apollo Subscription
Here's the real savings breakdown:
Apollo Basic Plan ($49/month):
- 900 exports monthly = 10,800 yearly
- Cost per lead: $0.054
Custom Apollo Scraper:
- Proxy service: $20/month = $240/year
- Unlimited exports
- Cost per lead: $0.00024 (assuming 100,000 leads/year)
Your scraper pays for itself after extracting just 5,000 contacts.
For agencies running multiple campaigns, the savings exceed $10,000 annually.
Alternative Method: Chrome Extension Approach
If coding isn't your strength, Chrome extensions offer a simpler path.
Tools like "Apollo Easy Scrape" automate extraction through the browser interface.
Installation Steps:
- Download the extension folder (search GitHub for "apollo scraper chrome extension")
- Open Chrome → Extensions → Enable Developer Mode
- Click "Load Unpacked" and select the folder
- Pin the extension to your toolbar
Usage:
- Navigate to your Apollo saved list
- Click the extension icon
- Set delay interval (5 seconds recommended)
- Click "Scrape List"
- Download CSV when complete
Extensions work great for small volumes (under 500 contacts). They break with UI updates and lack advanced features like proxy support.
Optimizing Your Apollo Scraper for Performance
Headless mode speeds up scraping by removing the browser UI:
options.add_argument('--headless')
options.add_argument('--disable-gpu')
This runs 2-3x faster but makes debugging harder.
Parallel scraping across multiple accounts scales throughput. Spin up 5 instances with different proxies and credentials.
Never run parallel scrapers on the same Apollo account. That's an instant ban.
Database storage beats CSV for large volumes. Use SQLite or PostgreSQL:
import sqlite3
def save_to_database(contacts):
conn = sqlite3.connect('apollo_leads.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS contacts (
name TEXT,
title TEXT,
company TEXT,
email TEXT,
location TEXT
)
''')
for contact in contacts:
cursor.execute('''
INSERT INTO contacts VALUES (?, ?, ?, ?, ?)
''', (contact['name'], contact['title'], contact['company'],
contact['email'], contact['location']))
conn.commit()
conn.close()
Databases index and query large result sets faster than scanning a flat CSV.
Common Errors and Troubleshooting
"Element not found" errors: Apollo updated its HTML structure. Inspect the page and update your CSS selectors.
Login fails repeatedly: Apollo detected automation. Switch to cookie-based authentication instead:
def load_cookies(self):
with open('apollo_cookies.json', 'r') as f:
cookies = json.load(f)
for cookie in cookies:
self.driver.add_cookie(cookie)
Scraper stops mid-execution: You hit rate limits. Reduce volume and increase delays.
No email addresses appear: Apollo restricts email reveals to verified accounts. Use a business email for signup.
FAQ
How many contacts can I scrape from Apollo per day?
Limit yourself to 1,000 contacts daily spread across 8-10 hours. This mimics normal user behavior and avoids triggering Apollo's anti-bot systems.
Can I scrape Apollo without a paid account?
Yes. Free Apollo accounts provide 10,000 email credits monthly. Your scraper bypasses export limits, so you can extract all 10,000 without upgrading.
What happens if Apollo detects my scraper?
First offense usually results in temporary account suspension (24-48 hours). Repeated violations lead to permanent bans. Always use proxies and reasonable rate limits.
How do I handle Apollo's CAPTCHA challenges?
Residential proxies and randomized delays prevent most CAPTCHAs. If they appear, services like 2Captcha ($3 per 1,000 solves) automate solutions.
Is building an Apollo scraper legal?
Scraping violates Apollo's Terms of Service, but it isn't illegal in most jurisdictions. Data privacy laws (GDPR, CCPA) restrict how you use scraped data, not collection itself. Consult a lawyer before commercial use.
Can I integrate my Apollo scraper with my CRM?
Yes. Most CRMs accept CSV imports. For real-time integration, use their APIs. Salesforce, HubSpot, and Pipedrive all offer Python libraries for programmatic data insertion.
Apify Apollo Scraper Alternative?
Yes. This is an alternative to the well-known Apify scraper, but it's totally free.