Yellow Pages Search Scraper

A category and a city,
as a lead table.

Type what you are looking for and where, and get the listings back as rows: the name, the phone, the street, the categories, the rating and review count, the opening hours, the website - and, where the enrichment resolves, contact emails with a deliverability verdict, social profiles and details read off the site itself. Sixty-three columns, one row per listing.

500 free rows, one-timethen $0.002 per row63 columnsCSV · XLSX · JSON
How it works

Two boxes in,
a lead table out.

The input is the same two things you would type into the site itself - what you want, and where you want it.

  1. STEP 1Sign in to the platform.
  2. STEP 2Open the Yellow Pages Search Scraper.
  3. STEP 3Pick the region.
  4. STEP 4Type the search term and the location.
  5. STEP 5Set a record limit, or leave it empty to take everything available.
  6. STEP 6Click Start scraping.

Both fields end up on every row, joined as one query value in the form search, location, so a file that mixes several searches is still separable afterwards.

Why teams use it

A directory listing,
already enriched.

The listing, then everything after it

The directory fields are only the first third of the row. The rest is enrichment: emails with a deliverability verdict, social profiles, and details read off the business's own website.

Emails that come with a verdict

Addresses arrive alongside a status rather than on their own, so a list can be filtered down to what is worth sending to before anyone loads it into a sequencer.

Hours in a machine-readable form

Opening times arrive as Mo-Fr 09:00-18:00, Sa 09:00-15:00 rather than prose, which is a form you can parse instead of a sentence you have to interpret.

What you get

Sixty-three columns -
and one thing to fix first.

This export has real data in it, so this page can be specific about formats. It also has one property that will quietly corrupt a pipeline, and it is worth two paragraphs before the table.

The column order is not stable between runs. Every run we have carries the same sixty-three names, but they do not always arrive in the same sequence - in one run hours sat second-to-last rather than twentieth, and the columns after it shifted by one. Nothing was added, removed or renamed; only the order moved.

That is harmless if you read by column name and destructive if you read by position. A loader that takes column 20 as amenities because it was amenities last week will fill that field with opening hours and never raise an error. Map the header row by name on every import - and if your tooling makes that awkward, this is the one thing worth fixing before the first real run rather than after it.

Data dictionary

Sixty-three columns,
read by name.

Taken from the header row and the JSON keys of real runs, which agree. Formats below are measured from populated cells - where a column has a fixed shape, it is given; where it does not, it is not invented.

name
The business name as the listing shows it.
phone
The main phone number, always in the form (212) 473-4444 - parentheses, a space, then a hyphen.
category
The categories as one string. This is exactly categories joined with a comma and a space, so the two are the same fact twice - take whichever suits you and ignore the other.
categories
The same categories as an array, which is the form to filter on.
area
The street line of the address. City, state and postcode are their own columns beside it.
city
The city.
state
The state, always two capital letters.
pincode
The postcode, always five digits.
range
The price-range indicator the listing can carry.
rating
The average rating, as a number in a string. It and reviews_count always arrive together - a listing has both or neither.
reviews_count
How many reviews that average is built on.
open_status
Whether the business was open at the moment that row was captured - open now, closed now, opening soon, open 24 hours. Read it against that row's scraped_at, not against the run; see the note below.
email
The single-address email field. The enrichment output lands in email_1 to email_3 and emails, which are the columns to read for contact addresses.
website
The business's own site. Every website-derived column below is empty unless this one is filled - though a filled website does not guarantee they resolved.
directions
A link to the directions page for the listing.
image
A link to the listing's thumbnail image.
years_in_business
How long the listing says the business has been trading, as a whole number.
description
A short snippet, truncated. Treat it as a preview rather than an about-text: some values are the business's own blurb and some are a customer review, which is why one can end mid-sentence or on a stray quotation mark.
source_url
The listing page the row was read from. The column to keep if you ever need to check a value by hand.
hours
Opening times in the compact form Mo-Fr 09:00-18:00, Sa 09:00-15:00 - two-letter day codes, ranges joined by commas.
amenities
Attributes the listing advertises. Two amenities can arrive in one value separated by a newline, so split on line breaks rather than assuming a single label.
facebook
Link to the business's Facebook page.
instagram
Link to the business's Instagram profile.
linkedin
Link to the business's LinkedIn page.
tiktok
Link to the business's TikTok profile.
medium
Link to the business's Medium publication.
reddit
Link to the business's Reddit presence.
skype
The business's Skype handle.
snapchat
Link to the business's Snapchat profile.
telegram
Link to the business's Telegram presence.
whatsapp
The business's WhatsApp contact.
twitter
Link to the business's X/Twitter profile.
vimeo
Link to the business's Vimeo channel.
youtube
Link to the business's YouTube presence - a channel, a user page or a single video, so do not assume a channel URL.
github
Link to the business's GitHub organisation.
crunchbase
Link to the business's Crunchbase profile.
emails
Every address the enrichment found, as an array.
emails_status
One entry per address in emails, each two comma-joined parts: a deliverability verdict, then a detail. The detail is not a fixed vocabulary - it can name the kind of mailbox or echo a domain - so switch on the part before the comma and treat the rest as free text.
website_title
The <title> of the business's site.
website_description
The meta description of the business's site.
website_keywords
The meta keywords of the business's site.
website_generator
What built the site, read from its generator tag - a CMS, a page builder or an SEO plugin, and often a version string with it.
website_has_fb_pixel
Whether a Facebook pixel was found on the site. A real boolean, not a string.
website_has_google_tag
Whether a Google tag was found on the site. Also a real boolean.
phones_extra
Further phone numbers found for the business, as an array. It can repeat the number already in phone, so de-duplicate against that column before dialling anything.
phones_extra_types
The line type for each entry in phones_extra, positionally aligned and always the same length - but an entry can be null where the type could not be determined, so index into it defensively.
phone_type
The line type of the main phone.
contact_name
A contact name from the enrichment. Do not assume this is a person - the values are as often a practice or company name as an individual, so it is not safe to split into first and last.
contact_title
The job title that goes with contact_name.
is_public
Whether the company is publicly listed. A real boolean.
wp_name
The company name as the phone-data provider holds it.
wp_address
The address as the phone-data provider holds it.
phones_extra_wp
Further phone numbers from the phone-data provider.
emails_persons
The people the enrichment attached to the found addresses, as an array.
employees
The company's headcount, as a number.
scraped_at
When that row was captured, as 2026-07-06 09:16:41.954000. This varies within a single run - rows in one file were not all read at the same instant, which is what makes open_status a per-row fact.
query
Your two inputs joined as search, location, repeated on every row that came from them.
position
The listing's place in the result order, starting at 1 and unique within a run. The column to sort on to reconstruct the ranking exactly as it was returned.
email_1
The first enriched email address. No row carries email_2 without this one.
email_2
The second enriched email address, when there is one.
email_3
The third enriched email address, when there is one.
industry
The industry the company-level enrichment assigns.
founded_year
The year the company was founded, as a number.

Read this export by column name, never by position. Every run carries the same sixty-three names, but the order is not fixed - in one of ours hours arrived second-to-last instead of twentieth, and everything after it shifted by one. Nothing was renamed or dropped; a positional loader would simply have written opening hours into the amenities field and reported success. The second thing to know is that scraped_at varies within a single file, because the rows were not all captured at the same instant - so open_status describes each row's own moment and is not a property of the run. And three smaller shapes worth handling before they surprise you: category is just categories joined by a comma, so it is the same fact twice; amenities can pack two values into one string separated by a newline; and phones_extra_types lines up with phones_extra index for index but can hold a null where the type was not determined.

Run controls

Set on the job,
not in the spreadsheet.

Four controls, and they are the whole input: where to search, what to look for, where to look, and how much to take. The sort and filter buttons beside the results are view controls - they shape what you are looking at, not what the run fetches.

Region Search term Location Limit (records) Empty limit takes everything One row per listing CSV export XLSX export JSON export
Common workflows

Three jobs this
runs more than any other.

A few examples of how teams use directory listings to answer a question they actually have.

Lead gen

Build a contactable list in one pass

A category and a city produce the listings; the enrichment columns produce the way to reach them. Because each address arrives with a deliverability verdict, the list can be filtered before it ever reaches a sending tool rather than after the bounces come back.

Lead gen · Sales
Market map

Size a local trade and see who is established

Rating, review count and years in business sit on the same row, which is enough to tell a crowded market from a thin one and a new entrant from a fixture - without opening a single listing by hand.

Research
Tech stack

Find businesses running a particular setup

The website columns say what built each site and whether it carries a Facebook pixel or a Google tag. For anyone selling to a platform's users, that turns a directory into a qualified list.

Go-to-market
Pricing

Pay only for the listings
you actually pull.

No subscription, no minimum, no recurring bill. Your first 500 rows are on us - after that you pay as you go, at the same flat rate as every other scraper here.

Free tier

500 free rows - $0

On every new account, one-time. No credit card. The record limit and every export format are included.

$0 forever
Pay as you go

$0.002 per row after the free tier

About $2 per 1,000 listings, enrichment columns included rather than billed as an extra step. The estimator shows the row count and credit cost before a run starts.

Most popular
Volume

Custom · high volume

Volume pricing, dedicated workers and an SLA for ongoing monitoring or very large historical pulls. Tell us your numbers and we will put together a quote.

Talk to us
10% off your first paid run.Use code LIVESCRAPER10 at checkout.
Sign up
Pairs well with

One directory,
and the ones beside it.

The legal bit

Is scraping
Yellow Pages legal?

Short answer: yes for the listing content - but this export carries contact data and a deliverability verdict, and that is the part that deserves your attention.

A Yellow Pages listing exists to be found. The name, phone, address, categories, hours and rating are shown to anyone who runs the search, signed in or not, and collecting publicly listed business information for market research is long-settled practice. Nothing here touches a login, an account or a paywall.

The enrichment is where care is owed. This export does not stop at the directory: it adds email addresses, the people attached to them, extra phone numbers with line types, and social profiles. A business address at a company domain is a business contact in most readings - but a named individual's address is personal data in the EU and the UK regardless of where it was published, and emails_persons exists precisely to name individuals. If you are doing outreach, the lawful basis and the opt-out are yours to get right, and the deliverability verdict in emails_status tells you whether a message will arrive, not whether you are allowed to send it. The two are unrelated and it is worth keeping them separate in your own head.

If your question is about market structure rather than contact - how many, how established, how well rated - drop the email, phone and person columns at ingest and most of this stops applying to you. We run no third-party trackers on the data layer, and your exports self-delete after 30 days. Yellow Pages' own terms restrict automated access, so check them before you scale.

livescraper.app · principles
Public business listings only
No logins, no accounts touched
Enriched emails and people are personal data
Deliverable is not the same as permitted
Exports self-delete (30 days)
Check Yellow Pages' own terms before scaling.
Common questions

What people ask
before signing up.

The questions we hear most. Something else? Talk to us - humans write the answers, not bots.

How do I scrape Yellow Pages?+
Using the Yellow Pages Search Scraper:
  1. Sign in to the platform.
  2. Open the Yellow Pages Search Scraper.
  3. Pick the region.
  4. Type the search term and the location.
  5. Set a record limit, or leave it empty to take everything available.
  6. Click Start scraping.
Why does my loader put the wrong data in a column?+
Because it is reading by position. Every run carries the same sixty-three column names, but the order is not fixed between runs - in one of ours the hours column arrived second-to-last rather than twentieth, and everything after it shifted by one. Nothing was renamed or dropped, so a positional loader mis-maps silently and reports success. Map the header row by name on every import and the problem disappears.
What comes back for each listing?+
Sixty-three columns. The directory fields are the name, phone, street, city, state, postcode, categories, rating and review count, opening hours, price range, a description snippet, an image and a link to the listing. The rest is enrichment: emails with a deliverability verdict, the people attached to them, extra phone numbers with line types, social profiles, and details read off the business's own website including what built it. All of them are in the CSV and XLSX as well as the JSON.
Is open_status reliable?+
It is accurate for the moment that row was captured, which is not the same as the moment the run finished. The scraped_at column varies within a single file because the rows were not all read at the same instant, so open now and closed now are per-row facts. Read open_status against that row's own scraped_at, and if you need opening times as a property of the business rather than a snapshot, use the hours column instead.
What format are the emails and their statuses in?+
The addresses arrive in emails as an array and are also flattened into email_1, email_2 and email_3. The ladder is consistent - no row has a second address without a first, or a third without a second. Each entry in emails_status is two comma-joined parts: a deliverability verdict, then a detail. The detail is not a fixed vocabulary and can name the kind of mailbox or echo a domain, so switch on the part before the comma and treat the rest as free text.
Can I split contact_name into first and last?+
Not safely. The values are as often a practice or company name as an individual, so a split on whitespace will produce nonsense for a good share of any list. If you need person-level fields, read emails_persons instead, and treat contact_name as a label rather than a name.
Which regions does it cover?+
There is a region selector on the form, and it marks any entry the parser does not yet handle - those show a warning that the site uses a different layout. The list is loaded when the page opens rather than fixed in advance, so check the dropdown for what is available to you rather than taking a list from this page. The default is the US site.
How much does it cost?+
The first 500 rows are free and one-time, with no credit card. After that it is $0.002 per row - about $2 per 1,000 listings - which is the same flat rate as every other scraper on the platform, with the enrichment columns included rather than charged as a separate step. The estimator shows the cost of a run before it starts.

Your first 500 listings,
on the house.

500 one-time free rows on every new account - no expiry date. After that $0.002 per row, pay as you go - no card on file until you say so.

Live instantly · no card required

Scraping Yellow Pages listings at scale

Livescraper's Yellow Pages Search Scraper turns a category and a location into a lead table. You pick a region, type what you are looking for and where, optionally cap the number of records, and download the results as a clean CSV, Excel or JSON file. One row comes back per listing, and both of your inputs are carried on every row as a single query value so a file that mixes several searches stays separable.

Each row carries sixty-three columns. The directory side is the business name, phone, street, city, state and postcode, the categories both as an array and as a joined string, the rating and review count, the opening hours in a compact machine-readable form, a description snippet, an image and a link back to the listing. The enrichment side adds email addresses with a deliverability verdict, the people attached to them, further phone numbers with their line types, social profiles, and details read off the business's own website - its title, description, keywords, what built it, and whether it carries a Facebook pixel or a Google tag.

Sales teams use it to build a contactable list in a single pass, filtering on the deliverability verdict before anything reaches a sending tool. Researchers put rating, review count and years in business side by side to tell a crowded local market from a thin one. Go-to-market teams filter on the website columns to find businesses running a particular platform.

One property of this export deserves attention before you build on it: the column order is not stable between runs. Every run carries the same sixty-three names, but in one of ours the hours column arrived second-to-last rather than twentieth and the columns after it shifted by one. Nothing was renamed or dropped, which is exactly why a loader that reads by position mis-maps silently and reports success - map the header row by name on every import. It is also worth knowing that scraped_at varies within a single file, so the open_status field describes each row's own moment rather than the run as a whole. Start free: your first 500 rows cost nothing and need no credit card, and after that it is a flat $0.002 per row.