Nextdoor Business & Reviews Scraper
No login. No session cookies. No browser.
Discovers Nextdoor businesses by city and category, then extracts 34 fields per business, the neighbor recommendations written about it and the demographics of the city it sits in. It reads only what Nextdoor's servers hand to a signed-out visitor, so there is no cookie to refresh and nothing that expires between runs.
oswaldocarabano/nextdoor-scraper
{
"cities": ["san-clemente--ca"],
"categories": ["Dentist", "Plumber"],
"maxBusinessesPerCity": 50,
"includeRecommendations": true,
"includeCityData": true
}- Version
- v0.1.24
- Memory
- 512 MB
- Browser
- none
- Proxy
- US residential IPs, preconfigured
Short answer
The Nextdoor Business & Reviews Scraper extracts public Nextdoor data without an account: business listings with contact details (phone filled on 93.9% of 741 measured businesses), neighbor recommendations classified into real reviews vs service requests at 95.6% accuracy, and city-level demographics. Pricing is pay-per-result at $0.008 per business and $0.002 per recommendation, and error rows are never charged.
Key points
- Runs signed-out: no account, no session cookies, nothing that expires between runs.
- 34 fields per business, with fill rates counted over 741 distinct businesses across 5 cities and 12 categories — not estimated.
- Every recommendation is classified as `recommendation`, `service_request`, `thanks` or `unknown`, at 95.6% accuracy on a hand-labelled set. Measured across 891 recommendations, 50% were service requests and only 19% actual reviews.
- Nextdoor's category directory is regional, not municipal. `onlyRequestedCity` filters during discovery, so a dropped business is never charged.
- Throughput measured on the platform at ~3,300 businesses/hour end-to-end at the default concurrency of 5.
- Neighbor posts and author neighborhoods are off by default, because a partial name next to a precise neighborhood can identify a real person.
What it does
Discovers Nextdoor businesses by city and category, then extracts 34 fields per business, the neighbor recommendations written about it and the demographics of the city it sits in. It reads only what Nextdoor's servers hand to a signed-out visitor, so there is no cookie to refresh and nothing that expires between runs.
{
"_type": "business",
"name": "Example Plumbing",
"slug": "example-plumbing-san-clemente-ca",
"categories": ["Plumber", "Water Heater Installation"],
"phone_number": "+19495550123",
"email": "hello@exampleplumbing.com",
"website_url": "https://exampleplumbing.com",
"address_full": "123 Avenida Del Mar, San Clemente, CA 92672",
"address_postal_code": "92672",
"hide_address": false,
"recommendations_count": 12,
"neighbors_talking_count": 34,
"recommendations_summary": "Neighbors mention fast response and fair pricing.",
"is_verified": true,
"source_city_slug": "san-clemente--ca",
"source_category": "Plumber",
"scraped_at": "2026-08-17T12:00:00.000Z",
"from_cache": false,
"data_age_hours": 0,
"_warnings": [],
"recommendations": [
{
"kind": "recommendation",
"kind_confidence": 0.92,
"kind_signals": ["praise", "past_service"],
"text": "They fixed our water heater the same day we called. Fair price too.",
"author_display_name": "Sarah M.",
"author_city": "San Clemente"
}
]
}Why this one
It does not ask you for your cookies
Most Nextdoor scrapers require you to paste session cookies from a logged-in browser. That works the day you set it up and breaks silently when the cookies expire. This Actor reads only the signed-out surface, so a run in six months behaves like a run today. The trade-off is stated openly: it cannot reach anything behind the login.
A classifier for a feed that lies about itself
Nextdoor's recommendation feed mixes praise, requests for a provider and bare thank-yous, and all three look alike. Scrape it raw and half of your "reviews" are neighbors asking whether anyone knows a good plumber — worthless as review data and actively misleading as sentiment input. Every row carries `kind`, `kind_confidence` and `kind_signals`, so you can raise the bar yourself instead of trusting a black box.
Fill rates that were corrected downward
An earlier version of the README quoted higher numbers measured on 30 businesses. At n=741 several came out lower — opening hours most of all, 57.4% rather than 77%. The published table is the corrected one. Anything not on it is not promised.
Cache metadata on every row
Rows can be served from a shared cache, which is why runs are fast and cheap. That is never hidden: `from_cache`, `fetched_at` and `data_age_hours` travel with every row, and `maxCacheAgeDays: 0` forces a fresh read.
Use cases
- Build local business directories with verified contact details for a city or trade area.
- Generate B2B lead lists for home services, dental, legal and other local categories.
- Analyse neighbor sentiment about local providers using only the rows that are actually reviews.
- Research a local market: income, average age, homeowner percentage and category coverage per city.
- Monitor what businesses publish about themselves through the posts dataset.
- Map a trade area rather than a municipality, using Nextdoor's distance-ordered directory on purpose.
Input
Every field has a default, and the defaults are deliberately small so a first run is cheap enough to inspect before you commit to a sweep. This table mirrors the Actor's own input schema field for field.
| Field | Default | What it does |
|---|---|---|
citiesstring[] | ["san-clemente--ca"] | CitiesNextdoor city slugs in the format `city-name--state`, lowercase, two-letter state. |
categoriesstring[] | ["Dentist"] | Business categoriesLeave empty to sweep every category a city exposes — Nextdoor publishes 54 per city. The per-city limit is split evenly between the categories you list, and whatever a small category cannot fill is handed to the others. |
onlyRequestedCityboolean | false | Only businesses in the requested cityNextdoor's directory is regional, not municipal. With this on, filtering happens during discovery, so a dropped business is never charged and the Actor stops paging once the city is exhausted. |
directBusinessUrlsstring[] | [] | Business URLsScrape these business pages directly, in addition to whatever discovery finds. |
maxBusinessesPerCityinteger | 50 | Max businesses per cityA per-city cap, shared evenly between categories. The default keeps a first run fast and cheap; raise it for a full sweep. |
includeRecommendationsboolean | true | Include neighbor recommendationsIndividual posts neighbors wrote about the business, with the author left exactly as Nextdoor anonymizes them, each classified by kind. |
maxRecommendationsPerBusinessinteger | 100 | Max recommendations per businessMeasured over 741 businesses: 2.5 each on average, 33 the most seen on one, and 57.6% have none at all. Raising this rarely changes the result. |
includeCityDataboolean | true | Include city dataOne row per city in a separate `cities` dataset: population, average income and age, homeowner percentage, safety and friendliness scores, all 54 categories and up to 852 neighborhoods. |
includeBusinessActivityboolean | false | Include business postsCorporate content the businesses published themselves. No neighbor personal data. |
includeCityPostsboolean | false | Include public neighbor postspersonal dataContains personal data: a partial author name and free text, sometimes about local safety incidents. Off by default. |
includeAuthorNeighborhoodboolean | false | Include the author's neighborhoodpersonal dataA partial name next to a precise neighborhood can identify a real person in a small community. Only applies if neighbor posts are enabled. |
expandNearbyCitiesboolean | false | Expand to nearby citiesDiscover neighbouring cities through Nextdoor's own cross-links, up to the hard cap below. |
maxExpandedCitiesinteger | 3 | Cap on expanded citiesA hard cap, and not optional: Nextdoor's city graph connects the whole of the United States, so without a limit one run could keep going indefinitely. |
maxConcurrencyinteger | 5 | Max concurrencyMeasured clean up to 5. At 10, Nextdoor returns HTTP 429 with a cooldown of about four minutes, which costs more time than the extra speed saves. |
maxCacheAgeDaysinteger | 7 | Maximum acceptable data ageSet 0 to force a fresh fetch of everything. Every row reports which it was. |
proxyConfigurationobject | { "useApifyProxy": false } | ProxyOptional. The Actor already routes through US residential IPs, so nothing needs configuring here. |
Output and fill rates
A field being in the schema is not the same as it having a value. The percentages below were counted on real runs; the sample sizes are in Measurements. Anything not listed here is not promised.
| Field | Filled | Meaning |
|---|---|---|
namestring | always | Business name as published. |
slugstring | always | Nextdoor's own business slug. |
categoriesstring[] | 84.2% | Nextdoor business categories. |
phone_numberstring | 93.9% | E.164 phone number. |
emailstring | 62.6% | Published business email. |
website_urlstring | 77.2% | Business website. |
address_fullstring | always | Street address, city, state and ZIP. |
address_postal_codestring | always | Derived by this Actor: Nextdoor exposes no ZIP field anywhere in its schema. |
hide_addressboolean | always | True when the business set its address to private. |
hours_open_statusstring | 57.4% | Opening hours as Nextdoor reports them. |
descriptionstring | 46.6% | Business self-description. |
recommendations_summarystring | 47.4% | Nextdoor's own summary of what neighbors say. |
gallery_urlsstring[] | 44.5% | Image gallery. |
recommendations_countinteger | always | How many recommendations exist. 0 for 57.6% of businesses. |
neighbors_talking_countinteger | always | Nextdoor's engagement counter. |
is_verifiedboolean | always | Nextdoor verification status. |
source_city_slugstring | always | The city slug this row was discovered under. |
source_categorystring | always | The category this row was discovered under. |
from_cacheboolean | always | Whether this row came from the shared cache. |
fetched_atdatetime | always | When the data was actually read from Nextdoor. |
data_age_hoursnumber | always | How old the data in this row is. |
recommendationsobject[] | always | Nested rows, each with `kind`, `kind_confidence` and `kind_signals`. |
Every key is always present. A field that exists but is empty comes back as explicit null, so a parser never has to guess.
Datasets
Different record types go to different datasets, so the main table never carries columns that are blank on most rows.
defaultOne row per business, with its recommendations nested inside.billedcitiesOne row per city: demographics, scores, category coverage, neighborhoods.billedpostsBusiness posts, and neighbor posts only if you opt in.billederrorsAnything that failed, with the reason, for traceability.never billed
Pricing
Pay per delivered result. Charges are applied as each row is produced rather than in a lump at the end, so an aborted run bills only for what it actually gave you.
| Event | Price | Notes |
|---|---|---|
actor-startActor start | $0.00001 | Effectively free. A run that finds nothing costs you nothing. |
businessBusiness | $0.008 | One business with 34 fields. Error rows are never charged. |
cityCity | $0.008 | One city: demographics, scores, categories and neighborhoods. |
recommendationRecommendation | $0.002 | One neighbor recommendation, classified by kind. |
postPost | $0.001 | One public post. |
Measurements
Each figure is shown with the method that produced it. A benchmark without a method is a marketing claim wearing a number's clothes.
Throughput
~3,300 businesses/hour
End-to-end on the Apify platform at the default concurrency of 5: 120 businesses plus 393 recommendations plus city data in 130 seconds, discovery included. The extraction stage alone runs at ~4,900/hour.
Classifier accuracy
95.6%
Hand-labelled validation set of neighbor recommendations.
Recommendation mix
50% service requests, 19% real reviews
891 recommendations across two real runs.
Recommendation coverage
42.4% of businesses have at least one
741 distinct businesses across 5 cities and 12 categories. Average 2.5 per business including zeros.
Directory locality
96-100% in-city for results 1-75, 0% past 76
Measured on san-clemente--ca asking for 200 dentists, counting per block of 25. San Clemente holds roughly 72 dentists; everything past that is the surrounding trade area.
Rate-limit ceiling
Concurrency 5 clean, 10 triggers a ~4 minute cooldown
Measured against Nextdoor's HTTP 429 response on the platform.
What it 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.
- No free-text business search. Nextdoor requires a login for that, so discovery runs through the public category directory: you find businesses by city and category, not by arbitrary keyword.
- No star ratings, because Nextdoor recommendations do not have them.
- No de-anonymized authors. Author names pass through exactly as Nextdoor publishes them and are never cross-referenced or resolved to real people.
- No addresses for businesses that set theirs to private: every address field returns `null` with a warning, even though coordinates are visible in the page source.
- United States only in this version.
Privacy
- Business contact details are published by the businesses themselves, for the purpose of being contacted.
- `includeCityPosts` is off by default: neighbor posts carry partial real names alongside a specific neighborhood and sometimes describe local safety incidents.
- `includeAuthorNeighborhood` is a separate opt-in on top of that, because a partial name plus a precise neighborhood can identify a real person in a small community.
- Removal requests: email privacy@actorstack.dev and the business or resident is added to an exclusion list for future runs.
See also the data removal process.
Frequently asked questions
Do I need a Nextdoor account or session cookies?
Are Nextdoor recommendations the same as reviews?
How much does a run cost?
Why does my run return businesses from other cities?
Can I search Nextdoor businesses by keyword?
Which countries are supported?
How fresh is the data?
Guides for this Actor
- Scrape Nextdoor business listingsA complete walkthrough: how Nextdoor exposes business data to signed-out visitors, how to select cities and categories, what a first run costs, and how to read the 34 fields you get back.
- Nextdoor API: what existsNextdoor has no public data API for business listings or recommendations. Here is what its actual interfaces cover, why the gap exists, and how to get structured data without one.
- Recommendations vs reviewsMeasured across 891 recommendations, 50% were neighbors asking for a provider and only 19% were actual reviews. Why the feed mixes three things, and how to separate them before they poison a sentiment model.
- Nextdoor data fieldsA field-by-field reference for the 34 attributes in a public Nextdoor business record, each with the percentage of 741 real businesses that had it filled in.
- Nextdoor city slugsNextdoor identifies a city as `city-name--state`. The rule sounds trivial and breaks on saints, hyphens and states that share a city name — here is the exact format and how to confirm a slug before spending a run on it.
- Scraping without cookiesMost Nextdoor scrapers ask for your session cookies. They work on setup day and fail silently later. The trade-off of refusing them, stated in both directions.
- Local lead generationWhich Nextdoor fields are usable for outreach, what the fill rates mean for a target list of a given size, and how to avoid building a list that is 40% dead ends.
- Nextdoor city dataThe city dataset is the least known part of Nextdoor's public surface and the most useful for market sizing: residents, income, age, homeownership, subjective scores and full category coverage.
- Trade area vs cityAsking Nextdoor for 200 dentists in one city returns the surrounding four towns too. We counted where the switch happens: results 1-75 were 96-100% local, everything past 76 was 0%.
- Is it legal?The interesting question is not "is scraping legal" but which specific data creates which specific obligation. Public business contact details and neighbor posts are not the same thing.