Nextdoor Scraper — Businesses, Reviews & Neighborhoods
Pricing
from $8.00 / 1,000 businesses
Nextdoor Scraper — Businesses, Reviews & Neighborhoods
Scrape public Nextdoor business listings, neighbor recommendations and city demographics. No login, no session cookies, nothing that expires.
Pricing
from $8.00 / 1,000 businesses
Rating
0.0
(0)
Developer
Oswaldo Carabano
Maintained by CommunityActor stats
0
Bookmarked
15
Total users
7
Monthly active users
0.41 hours
Issues response
15 days ago
Last modified
Share
Nextdoor Business & Reviews Scraper
Extract public Nextdoor business listings, neighbor recommendations and city demographics as structured JSON, CSV or Excel.
No login. No session cookies. No browser. Nothing you have to refresh, and nothing that expires between runs.
Why that matters more than it sounds
Most Nextdoor scrapers ask you for your session cookies. That works on the day you set it up and breaks when the cookies expire — and when it breaks, there is nothing you can do about it except paste new cookies and hope.
This Actor reads only what Nextdoor's own servers hand to a signed-out visitor. There is no account, no session and no cookie jar, so there is nothing to go stale. A run today behaves like a run in six months.
That is a deliberate design constraint, not a missing feature. It also means the Actor cannot reach anything behind Nextdoor's login — see What this Actor will not do.
What you get
One row per business in the main dataset, with its recommendations nested inside. Two ready-made views: Businesses (one row each) and Recommendations (one row per recommendation, business as context).
City data, posts and any error rows go to their own separate datasets — cities,
posts, errors — so the main table never has blank rows in it.
1 · business — the primary dataset
34 fields per business: name, categories, phone, email, website, full address with ZIP, coordinates, opening hours, verification status, gallery, Nextdoor's own summary of what neighbors say, and more.
Measured fill rates — counted over 741 distinct businesses across 5 cities and 12 categories. These are counts from real runs, not estimates:
| Field | Filled |
|---|---|
phone_number | 93.9 % |
categories | 84.2 % |
website_url | 77.2 % |
email | 62.6 % |
hours_open_status | 57.4 % |
recommendations_summary | 47.4 % |
description | 46.6 % |
gallery_urls | 44.5 % |
An earlier version of this page quoted higher numbers for some fields, measured on a sample of 30. At n = 741 several came out lower — opening hours most of all, 57 % rather than 77 %. The table above is the one to trust, and it is the one we will keep correcting as the sample grows. Anything not listed here is not promised.
Anything not on that list is not promised. address_postal_code is derived by this
Actor, because Nextdoor does not expose a ZIP field anywhere in its schema.
2 · recommendation — with a classifier you will not find elsewhere
Nextdoor's recommendation feed mixes three different things that all look alike: people praising a business, people asking for one, and people just saying thanks. Scrape it raw and your "500 reviews" are largely neighbors asking "anyone know a good plumber?" — which is worthless as review data and poisonous as sentiment input.
Every row gets a kind field:
kind | What it is |
|---|---|
recommendation | Actual praise or criticism of a business |
service_request | Someone looking for a provider, not reviewing one |
thanks | Acknowledgement with no substance about the business |
unknown | Below the confidence threshold — flagged, not guessed |
How much this matters, measured across two real runs (891 recommendations): 50 %
came back service_request — neighbors asking for a provider — against 19 %
actual recommendations. Scrape the feed raw and half your "review data" is noise
pointing the wrong way.
Accuracy: 95.6 % on a hand-labelled validation set. Each row also carries
kind_confidence and kind_signals, so you can raise the bar yourself instead of
trusting a black box.
A note on wording. Nextdoor calls these recommendations, not reviews. They are free-text posts from neighbors, they have no star rating, and Nextdoor anonymizes the author (typically a first name and last initial). If you need numeric ratings, this is not that dataset. What you get is what people actually wrote — which for most local-market research is the more useful half.
Dates and de-duplication. Every recommendation carries recommendation_id and
created_at, so you can tell new from old and re-scrape the same business without
counting anything twice:
| Field | What it is |
|---|---|
recommendation_id | Stable identifier. Same value every run, so it is the key to de-duplicate on |
created_at | Publication time, ISO 8601 UTC, same format as post rows |
created_at_epoch_ms | The same instant in Unix epoch milliseconds |
source_type | What it was posted on: post or comment |
Measured over 976 recommendations from 318 businesses across 5 cities and 12
categories, and re-checked on 1,817 recommendations across 8 full example runs:
100 % carry both recommendation_id and created_at.
De-duplicate on (business_slug, recommendation_id), not on the ID alone. The ID
identifies the neighbor post the recommendation was written on, and one post can
recommend several businesses: in the 1,817-row sample, 112 IDs appeared under more
than one business, which is a single "anyone know a good hair salon?" thread naming
four different salons. Those are four real recommendations, not duplicates. Within
one business the pair is effectively unique, and where it repeats it is because
Nextdoor served the same comment twice, which is exactly the duplicate you want
collapsed.
Paginating the Recommendations view?
limitandoffsetapply to the parent business rows, not to the flattened recommendation rows, so a smalllimitcan return zero rows even though the dataset is full. Fetch the view withoutlimit, or page by business and expect a variable number of recommendations per page.
Do not de-duplicate on
tracking_id. It is a per-request token that Nextdoor regenerates on every fetch: measured, 0 of 25 matched across two consecutive runs of the same page. It stays in the output for compatibility, butrecommendation_idis the one that persists. An earlier version of this page calledtracking_ida de-duplication key. That was wrong, and a customer found it before we did.
Measured over the same 741 businesses: 42.4 % have at least one recommendation,
averaging 2.5 each across all businesses. Plan for that — more than half of any
local category has none, and those businesses are still returned with
recommendations_count: 0 so your row count stays predictable.
3 · city — demographics and market context
Residents, average income and age, homeowner percentage, safety / friendliness / affordability scores, all 54 business categories Nextdoor tracks, up to 852 neighborhoods, and counts of classifieds, local groups and events.
4 · posts dataset — optional
Business posts are corporate content published by the businesses themselves. Neighbor posts are off by default — see Privacy.
Where each thing lands
| Dataset | Contents |
|---|---|
| default | one row per business, recommendations nested inside |
cities | one row per city: demographics, scores, neighborhoods |
posts | business posts and, if enabled, neighbor posts |
errors | anything that failed, for traceability — never charged |
Input
Paste a city and go. Every field has a sensible default, and the defaults are
deliberately small: a first run finishes in about a minute and costs under $0.50, so
you can see the real data before committing to a full sweep. Raise
maxBusinessesPerCity when you want one.
How long a run takes, and what happens if it runs out of time. Rows start appearing within seconds and keep coming as the run goes: results are not held back to the end. One city with the default 50 businesses takes about a minute; twenty cities with 100 each take around half an hour, so raise the run timeout before a sweep that big. Cities are processed in the order you give them and each is finished before the next starts, so if the run does hit its timeout it stops cleanly and you keep complete cities rather than every city half done — and you are only charged for what was delivered.
{"cities": ["san-clemente--ca"],"categories": ["Dentist", "Plumber"],"maxBusinessesPerCity": 50,"includeRecommendations": true,"includeCityData": true}
City slugs: the rule, and the two traps
A city slug is city-name--state: the city name in lowercase, spaces turned into
hyphens, then two hyphens and the two-letter state. It is the same slug that appears
in the URL of that city's page on Nextdoor, so when in doubt, open the city there and read
the address bar.
San Diego, CA → san-diego--caWinston-Salem, NC → winston-salem--ncOklahoma City, OK → oklahoma-city--ok
Trap 1 — apostrophes are deleted, not turned into hyphens.
Coeur d'Alene, ID → coeur-dalene--id (not coeur-d-alene--id)O'Fallon, MO → ofallon--mo (not o-fallon--mo)
Trap 2 — "Saint" is abbreviated, "Mount" and "Fort" are not. This is the one worth reading twice, because the wrong form does not fail: Nextdoor serves a real page for it, with the right city name and an empty business directory. Measured:
| Wrong form | What it returns | Right form | |
|---|---|---|---|
saint-louis--mo | Saint Louis, MO — 0 categories | st-louis--mo | 54 |
saint-paul--mn | Saint Paul, MN — 0 | st-paul--mn | 54 |
mt-pleasant--sc | Mt Pleasant, SC — 0 | mount-pleasant--sc | 54 |
ft-worth--tx | Ft Worth, TX — 0 | fort-worth--tx | 54 |
So a run can come back green, with city demographics and zero businesses, purely because of the spelling. The actor now spots these three patterns and tells you the form to use instead, in the log and in the error row — but it is cheaper to write it right the first time.
Everything else behaves: two cities with the same name in different states are distinct
(springfield--il and springfield--mo both work), New York and Washington DC are plain
(new-york--ny, washington--dc), and boroughs have their own pages (brooklyn--ny).
To find cities you do not already have, turn on expandNearbyCities: it follows
Nextdoor's own cross-links from the cities you named and reports the neighbours it found,
capped by maxExpandedCities. It needs a starting city — there is no way to list every
city Nextdoor covers, because it covers essentially all of them.
The 54 categories
Leave categories empty to sweep all of them. These 54 are the same in every city —
Nextdoor publishes one fixed directory and only the businesses inside it change:
Air Conditioning Fast Food Restaurant Mexican RestaurantAmerican Restaurant Fence Builder Nail SalonAppliance Repair Service Flooring Service NannyAuto Mechanic General Contractor PainterBabysitter Grocery Store Personal AssistantBakery Hair Salon Pet SitterBar Handyman Pizza PlaceBathroom Remodeling Service Healthcare PlumberBody Shop Heating And Cooling Service Pool CleanerBreakfast And Brunch Home And Garden Pressure WashingBurger Restaurant House Cleaner Professional ServicesCarpenter Insurance Agent Real Estate AgentClothing Store Kitchen Remodeler Real Estate BrokerCoffee Shop Landscape Architect RestaurantConstruction Landscape Contractor RooferDentist Lawn Service Tree ServiceDog Walker Lawyer TutorElectrician Medical And Dental Veterinarian
Either form works: the display name as written above, or its slug — Real Estate Agent
and real-estate-agent are the same category. Matching ignores case. A name that is not
on this list simply matches nothing, so a run that returns fewer businesses than you
expected is worth checking against it first.
Your per-city budget is split evenly between the categories you ask for. Asking for
["Plumber", "Dentist"] with a limit of 200 gives you roughly 100 of each, not 200
dentists and no plumbers — and whatever one category cannot fill is handed back to the
others rather than lost.
⚠️ Not every city has a directory. Measured: dana-point--ca returns no categories
at all while san-clemente--ca and laguna-niguel--ca have all 54. When that happens the
run says so in the log, writes an error row, and charges you nothing for the businesses
that do not exist.
How Nextdoor orders a city directory — worth 30 seconds
Nextdoor's category directory is ordered by distance. It serves every business in the city you asked for, and once that list runs out it keeps going into neighbouring towns. The switch is abrupt, not a gradual blend.
We measured it on san-clemente--ca, asking for 200 dentists, and counted how many
of each block of 25 were actually in San Clemente:
| Results | In San Clemente |
|---|---|
| 1–75 | 96–100 % |
| 76–200 | 0 % |
San Clemente simply has ~72 dentists. Everything past that point is the surrounding trade area — San Juan Capistrano, Dana Point, Ladera Ranch, Laguna Niguel.
What this means for you in practice:
- Keep
maxBusinessesPerCitynear what a city plausibly holds and you get that city, full stop. Our 120-business run came back 92 % San Clemente with no filtering. - Set it far higher and the surplus is regional overflow. Useful if you want the trade area — surprising if you didn't.
onlyRequestedCity: truekeeps only the city you named. Filtering happens during discovery, so you are never charged for a dropped business, and the Actor stops paging once the city is exhausted instead of burning through the region.
Every row carries address_city either way, so you can always split it yourself.
When you request several categories, the per-city limit is split evenly between them, and whatever a small category cannot fill is handed to the others. Ask for plumbers and dentists and you get both, not 200 dentists.
You can also skip discovery entirely and pass business URLs directly in
directBusinessUrls.
Pricing
Pay per result. You are never charged for a row that was not delivered, and error rows are never charged at all.
| Event | Price |
|---|---|
| Actor start | $0.00001 — effectively free |
business | $0.008 |
city | $0.008 |
recommendation | $0.002 |
post | $0.001 |
Starting the Actor costs $0.00001 — Apify does not allow a literal $0 event — so a
run that finds nothing costs you a hundred-thousandth of a dollar, which is as close
to nothing as the platform permits. Set
maxBusinessesPerCity, or a spend limit on the run, and the Actor stops cleanly at
the limit — no half-written rows.
Speed and politeness
Measured on the platform: ~3,300 businesses/hour end-to-end at the default concurrency of 5 — that is 120 businesses plus 393 recommendations plus city data in 130 seconds, discovery included. The extraction stage alone runs at ~4,900/hour.
The Actor deliberately caps concurrency at 5 and keeps a delay between requests. Pushing harder triggers rate limiting that costs more time than it saves — we measured a ~4 minute cooldown after tripping it — so when Nextdoor pushes back, the whole run pauses for minutes rather than hammering through a penalty window. Slower than a scraper that ignores this, and it finishes; faster in practice.
Requests go out through US residential IPs. You do not need to configure a proxy.
Data freshness
Results may be served from a shared cache, which makes runs faster and cheaper. Every row tells you exactly what you got:
from_cache— whether this row came from cachefetched_at— when the data was actually read from Nextdoordata_age_hours— how old it is
Set maxCacheAgeDays: 0 to force a fresh fetch on every row.
What this Actor will not do
Stated plainly so you can judge fit before spending anything:
- No logged-in content. No private groups, no member feeds, no direct messages, nothing that requires an account.
- No free-text business search. Nextdoor requires a login for that, so discovery runs through the public category directory instead. You find businesses by city and category, not by arbitrary keyword.
- No star ratings. Nextdoor recommendations do not have them.
- No de-anonymized authors. Author names are passed through exactly as Nextdoor publishes them and are never cross-referenced, enriched or resolved to real people.
- No addresses for businesses that hid theirs. When a business sets its address
to private — common for people working out of their homes — every address field
comes back
nullwith a warning, even though the coordinates are technically visible in the page source. - United States only in this version.
Privacy and personal data
Business contact details are published by the businesses themselves, for the purpose of being contacted.
Neighbor content is treated differently. includeCityPosts is off by default
because neighbor posts carry partial real names alongside a specific neighborhood,
and sometimes describe local safety incidents. includeAuthorNeighborhood is a
separate opt-in on top, because a partial name plus a precise neighborhood can
identify a real person in a small community. If you turn these on, you are
responsible for how you use the results — including under CCPA, if that applies to
you.
Removal requests: if you are a business owner or resident and want your information excluded from future runs, email privacy@actorstack.dev and it will be added to an exclusion list.
Not affiliated with Nextdoor
This Actor is an independent tool. It is not affiliated with, endorsed by, sponsored by or connected to Nextdoor, Inc. in any way. "Nextdoor" is a trademark of its owner, used here only to describe what this Actor reads.
It collects only data that Nextdoor's servers serve publicly to visitors who are not signed in. You are responsible for complying with the laws that apply to you when you use the output.
Output sample
Every field is always present. A field that exists but is empty comes back as
explicit null — keys are never dropped, so your parser never has to guess.
The nested recommendations omit scraped_at, _type, _warnings and
business_id, because the business row already carries all four and the
Recommendations view lifts the nested keys up to the top level — two keys with the
same name would silently overwrite each other.