Local Business Leads - Emails, Phones, Websites (OSM)
Pricing
from $3.20 / 1,000 business with contact data
Local Business Leads - Emails, Phones, Websites (OSM)
Find local businesses by category and city from OpenStreetMap: name, address, phone, website, social links and MX-verified emails read from their own sites. Pay only for businesses with contact data. Not a Google Maps scraper.
Pricing
from $3.20 / 1,000 business with contact data
Rating
0.0
(0)
Developer
Andrew Boiko
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
Local Business Leads - Emails, Phones, Websites (OpenStreetMap)
Build a list of local businesses for any category and place: name, address, phone, website, social links and a public email address that is read from the business's own website and checked for a working mail server (MX). The data comes from OpenStreetMap, the open map database, so there is no Google Maps scraping, no login and no API key.
Not a Google Maps scraper. OpenStreetMap is community-maintained: coverage and contact details differ a lot between countries and cities. Read the "Limits" section before you buy a big list.
Who is it for
- Freelancers and agencies who need local prospects for outreach (web design, SEO, bookkeeping, cleaning, marketing services).
- Sales teams building a first-pass list of tradespeople, clinics, shops, hotels or restaurants in a city.
- Researchers and market analysts who want category counts and addresses for a region.
- Developers who need a clean JSON/CSV feed of businesses by category and location.
What you get
For every business that has a name and at least one contact detail:
- Name, category, subcategory, address parts, city, postcode, country code
- Phone numbers (as written in OSM, normalised to
+49...form when the number is international) - Website, Facebook, Instagram, LinkedIn, X/Twitter when listed in OSM
- Email with a status:
verified_mx(the domain accepts mail),unverified, ornone, and where it was found (osmorwebsite:/contact) - Opening hours (OSM syntax), latitude/longitude, OpenStreetMap link
- Stable
idsuch asnode/123456789for deduplication across runs
Input
| Field | Type | Default | Description |
|---|---|---|---|
searches | array | required | Items like {"query": "dentist", "location": "Berlin, Germany"} or the string "dentist in Berlin" (also "dentist | Berlin"). Up to 100 searches. |
maxResultsPerSearch | integer | 100 | 1-2000 businesses saved per search. Only places with a name and a contact detail count. |
onlyWithWebsite | boolean | false | Keep only places that list a website in OSM. |
findEmails | boolean | true | Read the business website (homepage + up to 3 contact/imprint/about pages), extract emails and MX-check them. |
includeFailed | boolean | false | Add a free rowType: "error" row for each search that failed (never charged). |
Categories: more than 100 common categories are mapped to OpenStreetMap tags (restaurant, cafe, dentist, doctor, pharmacy, lawyer, accountant, plumber, electrician, hairdresser, beauty salon, gym, hotel, car repair, bakery, supermarket, real estate, veterinary, school and many more) including synonyms in English, German, French, Spanish and Ukrainian. You can also type a raw OSM tag such as amenity=dentist. Unknown words fall back to a search in business names.
Output example
{"rowType": "business","id": "node/1001","name": "Zahnarztpraxis Dr. Müller","category": "dentist","subcategory": "dentist","address": "Friedrichstraße 12, 10117, Berlin","street": "Friedrichstraße","houseNumber": "12","city": "Berlin","postcode": "10117","country": "DE","phone": "+49301234567","phones": ["+49301234567", "+49307654321"],"website": "http://mueller-dental.example/","email": "praxis@mueller-dental.example","emailStatus": "verified_mx","emailSource": "osm","otherEmails": [],"facebook": "https://www.facebook.com/mueller.dental","instagram": "https://www.instagram.com/mueller_dental","linkedin": null,"twitter": null,"openingHours": "Mo-Fr 08:00-18:00","lat": 52.520123,"lon": 13.404988,"osmUrl": "https://www.openstreetmap.org/node/1001","searchQuery": "dentist in Berlin, Germany","source": "OpenStreetMap (Overpass API)","attribution": "© OpenStreetMap contributors (ODbL)","scrapedAt": "2026-10-14T09:30:00.000Z"}
Each run also writes an OUTPUT record (counts, charged events, skipped places with reasons, warnings, stoppedReason) and a short RESULTS_MD summary to the default key-value store.
Pricing
Pay only for results (pay per event). No monthly rental.
| Event | Price | When it is charged |
|---|---|---|
business | $0.004 | One business with a name and at least one contact field (phone, website, email or social link). |
verified-email | $0.008 | Extra, only when an email was found for that business and its domain passed the MX check. |
So a business with an email costs $0.012, one without an email $0.004. 1,000 businesses cost between $4 and $12 depending on how many have a verified email. Apify adds volume discounts for paid plan tiers (Bronze, Silver, Gold). You are never charged for failed searches, places without contact data, duplicates, or anything beyond the maximum cost per run that you set. Free-plan users can try the actor with their free monthly credit.
How it works
- Each location is geocoded with OpenStreetMap Nominatim (1 request per second, identified user agent).
- The category is translated to OSM tags and sent to the Overpass API as a query over the place's area. If a public Overpass server is busy (HTTP 429/504), the actor rotates to mirror servers with backoff; for very large areas that time out it falls back to smaller map tiles.
- Places without a name are dropped; duplicates (the same OSM object found by several searches) are removed.
- If
findEmailsis on, the business website is read politely: robots.txt is respected, one request per host at a time with a pause, small page-size limits, honest user agent. Only addresses on the business's own domain (or a free mailbox such as Gmail published on the page) are kept; web agency and widget addresses are ignored. - The email domain is checked for MX records. Only results that pass are billed as
verified-email. - Progress is saved, so a restarted or migrated run never charges or outputs the same place twice.
Limits and honest caveats
- Coverage depends on OpenStreetMap. Western and Central Europe is dense; other regions can be sparse. Many OSM places have no phone or website and are therefore skipped (and not charged).
- Email coverage is partial. Expect emails for a minority to roughly half of businesses that have a website, depending on country. Contact forms without a visible address, JavaScript-only sites, and sites that block robots yield nothing.
verified_mxmeans the email's domain can receive mail. It does not prove that the mailbox exists or that the address is read by a person. We do not probe mail servers (no SMTP).- Results are capped by Overpass limits; very large areas may be truncated (a warning is added to
OUTPUT). Use a city or district rather than a whole country. - Opening hours, phone formats and categories are community data and can be outdated or inconsistent.
- No reviews, ratings, photos or prices: that data does not exist in OpenStreetMap.
Legal and ethical notes
- Business data from OpenStreetMap is licensed under the Open Database License (ODbL). If you publish or share the data or a derived database, you must credit "© OpenStreetMap contributors" and comply with ODbL (share-alike for derived databases). The
attributionfield is included in every row. - Only publicly available business contact data is collected. Business email addresses may still be personal data under GDPR/ePrivacy rules in your jurisdiction. You are responsible for having a lawful basis, honouring opt-outs and following anti-spam laws (CAN-SPAM, GDPR/PECR, CASL) when you contact people.
- Website reading respects robots.txt and uses modest request rates. The actor uses the public Nominatim and Overpass services under their usage policies; for large commercial volumes consider your own mirrors (see FAQ).
FAQ
Is this a Google Maps scraper? No. It uses OpenStreetMap only. It does not access Google data.
Why did I get fewer results than I asked for? OSM may simply not contain that many named places with contact data in the area. Check OUTPUT.skipped and OUTPUT.warnings in the key-value store.
Do I pay for businesses without a phone, website or email? No. They are skipped and not charged.
How accurate are the emails? They are public addresses read from the business's own pages; verified_mx only means the domain can receive mail. Expect some outdated or role addresses such as info@.
Can I search a whole country? You can, but public Overpass servers may truncate or time out. Split by city or region.
Which languages are supported for categories? English plus common German, French, Spanish and Ukrainian words. Others fall back to a name search, or use raw tags like shop=bakery.
Can I use my own Overpass server? The actor reads the OVERPASS_URL, OVERPASS_MIRRORS and NOMINATIM_URL environment variables; set them in the actor's environment variables for private mirrors.
Why is a run slow? Geocoding is limited to 1 request per second and websites are fetched politely. Turn off findEmails for faster runs.
Use it via API
Replace YOUR_USERNAME and the token. The actor ID is YOUR_USERNAME~local-business-leads.
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~local-business-leads/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"searches":[{"query":"dentist","location":"Berlin, Germany"}],"maxResultsPerSearch":50}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('YOUR_USERNAME/local-business-leads').call({searches: ['plumber in Hamburg, Germany'],maxResultsPerSearch: 100,onlyWithWebsite: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.length, items[0]);
from apify_client import ApifyClientclient = ApifyClient("APIFY_TOKEN")run = client.actor("YOUR_USERNAME/local-business-leads").call(run_input={"searches": [{"query": "bakery", "location": "Vienna, Austria"}],"maxResultsPerSearch": 100,})items = client.dataset(run["defaultDatasetId"]).list_items().itemsprint(len(items))
Integrations
Use the Apify integrations for Make, n8n, Zapier, Google Sheets, Airtable, Slack and webhooks: start the actor on a schedule, then send each dataset item to your CRM or spreadsheet. Export formats include JSON, CSV, Excel and XML. Typical flow: Schedule -> run actor -> filter emailStatus = verified_mx -> add rows to your CRM.
Support
Found a category that does not map well, or a country with missing data? Open an issue on the actor page with the search you used and the expected result.
More tools by the same author
- Website Contact Extractor: Emails, phones and social links from any list of websites
- B2B Email Verifier: Verify business emails and guess address patterns
- Domain to Company Enrichment: Turn domains into company profiles
- Decision-Maker Contacts: Founders, CEOs and department heads from company websites