Bing Maps Scraper — Business Data & Leads avatar

Bing Maps Scraper — Business Data & Leads

Pricing

from $2.00 / 1,000 results

Go to Apify Store
Bing Maps Scraper — Business Data & Leads

Bing Maps Scraper — Business Data & Leads

Turn Bing Maps into a clean local-business dataset. Search keywords across cities, map whole markets by category, enrich with addresses, opening hours, emails & socials, and stream results in real time to your dataset or webhook. 10,000+ businesses per run — ready for CRM, Sheets & AI.

Pricing

from $2.00 / 1,000 results

Rating

0.0

(0)

Developer

Emmanuel

Emmanuel

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Bing Maps Real-Time Data

Turn Bing Maps into a clean, structured local-business dataset. Search many keywords and cities in one run, map a whole local market by category, enrich every business with address breakdown and opening hours, find contact emails, resolve the specific business links you already have, and stream it all to your dataset — and to your own systems — in real time.

Built for lead-generation agencies, sales teams, franchise and market researchers, data engineers, and AI workflows that need dependable local business data at scale, without slow or brittle tooling.

The downloaded dataset is JSON/CSV/Excel — no code required to get value from it.

⚠️ This is a paid Actor. Apify accounts on the free plan receive a free sample of 2 businesses and a clear reminder to upgrade. Paying accounts get the full, uncapped dataset. See Plans & free tier.


Why teams choose this Actor

Bing Maps Real-Time DataTypical alternatives
SpeedFirst rows within seconds of startingOften 5–15 s per business
Memory512 MB default2–4 GB+
ReliabilityTransient failures are retried automatically, and one bad business never breaks the runOne failure can abort the job
SetupOrganised input UI with sensible defaults — run it immediatelyFrequently fragile and high-maintenance
CostLow compute, efficient proxy use, hard maxItems budget capUnpredictable
OutputFlat, normalised rows — ready for Sheets, CRM, or an LLMRaw pages to post-process
Scale10,000+ businesses per run, many markets at onceUsually capped much lower
SourceBing Maps: strong SMB coverage and ratings aggregated from Yelp/TripadvisorSingle-provider listings

Quick start

  1. Add your searches. In Search terms & locations, type a keyword and a city — for example coffee shops in Seattle, WA. Add more rows for more markets.
  2. Click Start. Rows stream into the run's dataset as they are found.
  3. Download. Open the Output tab → All results, and export as JSON, CSV, or Excel. Or read the dataset over the Apify API.

Minimal input that returns a rich dataset:

{
"searchTasks": [
{ "query": "coffee shops", "location": "Seattle, WA", "placesPerQuery": 50 },
{ "query": "bakeries", "location": "Portland, OR", "placesPerQuery": 50 }
],
"fetchEmails": true,
"maxItems": 200
}

What you get — 30+ data points per business

Every row is flat and normalised — no nested surprises — and tagged with featureType and scrapedAt so you can filter, join, and pipe it anywhere.

GroupFields
Identitytitle, category, placeId, ypid, bingUrl
Locationaddress, addressLine, city, state, postalCode, country, latitude, longitude
Contactphone, website, emails[], socials[]
Reputationrating, reviewCount, ratingSource
OperationsopenStatus, permanentlyClosed, openingHours
MediaimageUrl
TraceabilityfeatureType, searchQuery, searchLocation, searchTaskIndex, searchTaskLabel, position, sourceUrl, linkMatch, scrapedAt

Example record

{
"featureType": "search",
"scrapedAt": "2026-09-22T01:05:19.015Z",
"title": "Storyville Coffee Pike Place",
"category": "Cafe",
"address": "94 Pike St Suite 34, Seattle, WA 98101",
"addressLine": "94 Pike St Suite 34",
"city": "Seattle",
"state": "WA",
"postalCode": "98101",
"country": "US",
"phone": "(206) 780-5777",
"website": "https://storyville.com/pages/pike-place-market",
"emails": ["info@storyville.com"],
"socials": [
"https://x.com/storyville",
"https://www.facebook.com/StoryvilleCoffee",
"https://www.instagram.com/storyville"
],
"rating": 4.5,
"reviewCount": 2616,
"ratingSource": "Yelp",
"openStatus": "Closed",
"permanentlyClosed": false,
"openingHours": {
"Monday": "06:59-17:00",
"Friday": "06:59-18:00",
"Saturday": "06:59-18:00",
"Sunday": "06:59-18:00"
},
"latitude": 47.60890579223633,
"longitude": -122.3405532836914,
"imageUrl": "https://www.bing.com/th?id=...",
"placeId": "ypid:YN6230075ECE10B067",
"ypid": "YN6230075ECE10B067",
"bingUrl": "https://www.bing.com/maps?q=Storyville%20Coffee%20Pike%20Place&filters=ypid%3A%22YN6230075ECE10B067%22",
"searchQuery": "coffee shops",
"searchLocation": "Seattle, WA",
"searchTaskIndex": 0,
"searchTaskLabel": "coffee shops | Seattle, WA",
"position": 1,
"sourceUrl": null,
"linkMatch": null
}

Every row carries exactly these fields — nothing extra, and no placeholder keys.


Features

🔎 Keyword search — multi-market in one run

Run many keyword + location pairs at once — coffee shops in Seattle next to plumbers in Austin next to dentists in Miami. Give each task its own result limit, and Bing's own listing data fills in name, category, address, phone, website, star rating, review count, rating source, coordinates, photo, open/closed status, and a direct Bing Maps link.

Use it for long-tail local lists: niche × city matrices, brand and competitor names, service categories, "everything in this metro" sweeps.

🎯 Precise area targeting — neighbourhoods, postal codes and exact circles

A city name is often too blunt: "dentists in Austin, TX" pulls listings from across the whole metro. Two levels of precision are available, and they combine well.

1. Target the location text (no setup). The location can be a city, a neighbourhood, or a postal code. Postcodes are the sharpest text option because they concentrate results in that area:

Location usedPlumbers returnedSpread around downtown Austin
Austin, TX173.8 km – 25 km (metro-wide)
downtown Austin93.8 km – 11.5 km
78701 (ZIP)50.8 km – 6.6 km

So for a tighter list, "plumbers" + "78701" beats "plumbers" + "Austin, TX" — no coordinates needed at all.

2. Draw an exact circle (optional). Add latitude, longitude and radiusMeters to a search task and only businesses inside that circle are exported. Every kept row carries distanceMeters, so you can sort by proximity or verify the filter:

{
"searchTasks": [
{
"query": "dentists",
"location": "Austin, TX",
"latitude": 30.2672,
"longitude": -97.7431,
"radiusMeters": 5000,
"placesPerQuery": 60
}
]
}
[INFO] Task 1/1: "dentists | Austin, TX" (within 5 km)
[INFO] Task "dentists | Austin, TX": 12/60 business(es) within 5 km
[INFO] 34 business(es) were outside the requested radius (or had no coordinates) and were excluded.

Notes to get good results:

  • Supply both coordinates. radiusMeters without latitude/longitude fails immediately with a clear message — we never guess a centre from a place name, so the circle you ask for is the circle you get. Coordinates are easy to copy from Bing Maps or any map tool.
  • Coordinates alone don't scope the search — the location text does. That is why a radius task also needs a location (use a postcode or neighbourhood for the tightest results).
  • A radius narrows, it doesn't expand. It can only filter the businesses the source returns for that query, so pair a small radius with a tight location and a generous placesPerQuery to give it enough to work with.
  • Businesses with no coordinates are excluded when a radius is active (they cannot be verified as inside it), and the count is reported in the log and run summary.

📡 Nearby discovery

Don't want to write keywords? Pick from 18 business categories (restaurants, hotels, cafes, gyms, dentists, doctors, lawyers, real estate, auto repair, and more) plus a city or area, and the Actor runs one search per category. Results are tagged featureType: "nearby".

Ideal for mapping a market, territory planning, franchise gap analysis, and competitor density studies.

🔗 Scrape by URL — enrich the businesses you already have

Already know which businesses you want? Paste their Bing Maps links (the bingUrl value from a previous run, or the address bar of a business page) and get the same field-rich record for each one — no keyword needed.

  • Every link becomes one row tagged featureType: "scrape_by_url", keeping the link in sourceUrl.
  • linkMatch tells you how precisely each link was matched:
    • business_id — the business matches the identity carried by the link. Fully verified.
    • business_name — resolved by name only: the link carried no identity, or the exact location could not be confirmed (common with multi-location brands, where Bing may return another same-name branch). Check address if you need a specific branch.
  • Lead filters are deliberately not applied to links — every business you list is exported.
  • A link that cannot be resolved is reported in the log and in the run summary's errors — never silently turned into a junk row.

🏢 Address breakdown & opening hours

With fetchPlaceDetails: true (default), each business also gets a structured address (addressLine, city, state, postalCode, country) and a weekly openingHours schedule such as { "Monday": "08:00-18:00" } — ready for routing, CRM enrichment, and "is this place open?" logic.

Enrichment is best-effort: a business that cannot be enriched is still exported, never dropped.

📧 Email & social discovery

Turn listings into contactable leads. With fetchEmails: true each business website is mined for the contact details it publishes, and you get:

  • emails[] — the reachable addresses behind the business (for example info@, sales@, or an owner's address), de-duplicated and cleaned.
  • socials[] — Facebook, Instagram, X/Twitter, LinkedIn, YouTube, TikTok, Pinterest, and more.

Placeholder and junk addresses (noreply@, analytics and CDN domains, template defaults) are filtered out automatically.

🎯 Lead & quality filters

Shape the list exactly how you sell it:

  • Minimum rating — skip low-reputation businesses
  • Require phone / require website — only contactable businesses
  • Category contains — one niche at a time (dentist, hotel, plumb)
  • Exclude closed — drop permanently/temporarily closed listings (on by default)

Combined with email discovery, requirePhone: true + minRating: 4 + fetchEmails: true produces an outreach-ready list in a single run.

⚡ Real-time delivery and webhooks

  • Streaming dataset — rows appear as they are collected, so you can read while the run is still working.
  • Webhooks — set webhookUrl and every record is also POSTed immediately to your endpoint (JSON or Slack-formatted): CRM, Zapier, Make, Google Sheets, a Slack channel, or your own pipeline. See Webhooks.
  • Apify integrations & schedules — trigger runs on a schedule and connect the dataset to Sheets, Airtable, HubSpot, and the rest of the Apify ecosystem.

Use cases

Sales & lead generation

  • Build outreach lists with phone, email, and website for niches by city
  • Refresh an old lead list with current addresses, hours, and contact details
  • Find permanentlyClosed businesses to clean up a CRM
  • Trigger a CRM push per new lead with webhooks
  • Proximity campaigns — everyone within a few kilometres of a store or clinic, sorted by distanceMeters

Market & location research

  • Count businesses per category per city for saturation and demand studies
  • Compare average ratings and review counts between regions and competitors
  • Map every dentist, gym, or cafe in a metro area with nearby discovery
  • Drill into one neighbourhood or ZIP code instead of an entire metro
  • Franchise expansion: find cities that are underserved in your category

Data & engineering

  • Backfill a warehouse with local business dimensions (stable placeId for joins and diffs)
  • Enrich an existing account list from the links you already store (scrape by URL)
  • Feed clean JSON into RAG, scoring models, or territory-planning tools
  • Schedule weekly snapshots and diff new vs. closed locations

AI & agents

  • Give an LLM structured local business records for outreach drafts and summaries
  • Run the Actor from an AI assistant through Apify MCP and read results in chat
  • Score and segment leads with your own model on top of the dataset

Plans & free tier

This is a paid Actor.

Your Apify planWhat happens
FreeYou get a free sample of 2 businesses plus a clear reminder to upgrade. Everything works exactly as documented — you just receive the sample instead of the full dataset, and nothing extra is charged.
Any paid plan (Bronze, Silver, Gold, Platinum, Diamond)Full output — every feature, with no plan-level caps beyond the maxItems you set.

The log always tells you exactly where you stand:

[INFO] Paying user — full output, tier: BRONZE.
[WARN] Free plan detected, tier: FREE — a free sample of 2 business(es) was exported.
Upgrade to a paid Apify plan for the full dataset.

A limited free run is not an error: it exits successfully, the sample is delivered like any other run, and the decision is recorded in the run summary (see Run summary).

Owner option. The sample size and behaviour are tunable from Apify Console → Actor → Source → Environment variables, with no code change:

VariableDefaultEffect
FREE_TIER_MODElimitlimit = hand out the sample below. block = export nothing for free accounts.
FREE_TIER_MAX_ITEMS2Total businesses in a free run.
FREE_TIER_MAX_USERS_PER_ACCOUNT2Businesses per search task in a free run.

Input reference

Every input has a sensible default — the pre-filled example runs as-is. Enable only what you need.

InputTypeDefaultDescription
Keyword search
enableSearchbooleantrueTurn keyword search on/off
searchTasksobject[]2 examplesPrimary input: { query, location, placesPerQuery?, latitude?, longitude?, radiusMeters? } per row
searchTasks[].locationstring—City, neighbourhood, or postal code — postcodes are the most precise text option
searchTasks[].latitude / longitudenumber—Optional exact centre. Enables distanceMeters on rows, and is required for a radius
searchTasks[].radiusMetersinteger—Keep only businesses within this many metres of that centre
placesPerQueryinteger20Default max businesses per task
maxPagesPerQueryinteger50Safety cap on depth per task — lower it for quick tests
Nearby discovery
enableNearbybooleanfalseDiscover businesses by category around one location
nearbyCategoriesenum[]5 defaults18 categories: restaurants, hotels, cafes, gyms, dentists, doctors, lawyers, real estate, …
nearbyLocationstring—City or area for nearby discovery
placesPerCategoryinteger20Max businesses per category
Scrape by URL
enableScrapeByUrlbooleanfalseResolve specific business links into full records (turns on automatically when links are pasted)
scrapeUrlsstring[][]One Bing Maps business link per row
Filters
minRatingnumber—Minimum star rating (0–5)
requirePhonebooleanfalseOnly businesses that list a phone
requireWebsitebooleanfalseOnly businesses that list a website
categoryFilterstring—Keep categories containing this text
excludeClosedbooleantrueSkip permanently/temporarily closed businesses
Enrichment
fetchPlaceDetailsbooleantrueStructured address + weekly opening hours
fetchEmailsbooleanfalseemails[] + socials[] from the business website
Output & limits
languagestringenLanguage for names and addresses
countrystringusCountry code for localised results and proxy routing
maxItemsinteger10000Hard cap on dataset rows for the run
webhookUrlstring—Additional real-time POST destination (the dataset is always written)
webhookFormatenumjsonjson (full record) or slack (message payload)
Connection
proxyConfigurationobjectApify residential, USChange country or supply your own proxy URLs

Advanced (API only): maxConcurrency, requestDelayMs.

Input examples

High-intent B2B list with emails

{
"searchTasks": [
{ "query": "dentists", "location": "Austin, TX", "placesPerQuery": 60 },
{ "query": "dentists", "location": "Dallas, TX", "placesPerQuery": 60 }
],
"minRating": 4,
"requirePhone": true,
"fetchEmails": true,
"maxItems": 200
}

Map a whole market by category

{
"enableSearch": false,
"enableNearby": true,
"nearbyCategories": ["cafes", "gyms", "beauty_salons"],
"nearbyLocation": "Denver, CO",
"placesPerCategory": 40,
"fetchPlaceDetails": true
}

Enrich businesses you already have links for

{
"enableSearch": false,
"scrapeUrls": [
"https://www.bing.com/maps?q=Storyville%20Coffee%20Pike%20Place&filters=ypid%3A%22YN6230075ECE10B067%22",
"https://www.bing.com/maps?q=Ghost%20Note%20Coffee&filters=ypid%3A%22YN73759BB6B824CAC4%22"
],
"fetchEmails": true
}

Push every new lead into your CRM as it is found

{
"searchTasks": [{ "query": "roofing companies", "location": "Phoenix, AZ" }],
"fetchEmails": true,
"webhookUrl": "https://your-crm.example.com/leads/incoming?token=YOUR_TOKEN",
"webhookFormat": "json"
}

Alert a Slack channel

{
"searchTasks": [{ "query": "new restaurants", "location": "Miami, FL" }],
"webhookUrl": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
"webhookFormat": "slack"
}

Output reference

Every dataset row is one business.

FieldTypeDescription
featureType"search" | "nearby" | "scrape_by_url"Which feature produced the row
titlestringBusiness name
categorystringPrimary category
addressstringFull address as listed
addressLine, city, state, postalCode, countrystring | nullStructured address (with fetchPlaceDetails)
phonestring | nullPhone number when listed
websitestring | nullWebsite URL when listed
emailsstring[]Contact emails (with fetchEmails)
socialsstring[]Social profile URLs (with fetchEmails)
ratingnumber | nullStar rating (0–5)
reviewCountinteger | nullNumber of reviews
ratingSourcestring | nullRating provider when Bing attributes it (e.g. Yelp, Tripadvisor)
openStatusstring | nulle.g. Open, Closed, Permanently closed
permanentlyClosedbooleanConvenience flag for closed listings
openingHoursobject | nullWeekly schedule, e.g. { "Monday": "08:00-18:00" }
latitude, longitudenumber | nullCoordinates
imageUrlstring | nullListing photo
placeIdstringStable business identifier — the dedupe and join key
ypidstringLocal business identifier
bingUrlstringDirect link to the business on Bing Maps
searchQuerystringKeyword or category that produced the row
searchLocationstringLocation used for the row
searchTaskIndexinteger0-based task index (for scrape_by_url, the index in scrapeUrls)
searchTaskLabelstringe.g. `"dentists
positioninteger | null1-based rank within the task
distanceMetersinteger | nullDistance from the task's centre when latitude/longitude are supplied — use it to sort by proximity
sourceUrlstring | nullThe link a scrape_by_url row came from
linkMatch"business_id" | "business_name" | nullHow a supplied link was matched (null for search/nearby rows)
scrapedAtstringISO timestamp

Deduplication: results are deduplicated by placeId across the whole run — search, nearby, and links combined. The same business is never exported twice.

Run summary (OUTPUT)

Each run also writes a summary to the key-value store, shown in the run's Output tab:

{
"features": ["search", "scrape_by_url"],
"searchTasks": 1,
"nearbyTasks": 0,
"scrapeUrls": 5,
"recordCount": 42,
"scrapeUrlsResolved": 5,
"filteredOutCount": 3,
"duplicateCount": 6,
"detailsFetched": 41,
"detailsFailed": 1,
"emailsFound": 27,
"pagesFetched": 4,
"webhooksDelivered": 42,
"webhooksFailed": 0,
"errors": [],
"spendingLimitReached": false,
"paywall": {
"detected": true,
"isPaying": true,
"pricingTier": "BRONZE",
"mode": "limit",
"limited": false,
"blocked": false,
"freeTierMaxItems": null,
"freeTierMaxPlacesPerTask": null
},
"startedAt": "2026-09-22T01:05:06.771Z",
"finishedAt": "2026-09-22T01:07:09.006Z",
"durationMs": 122235
}

The paywall object documents the plan decision transparently: detected (whether Apify plan signals were present), isPaying, pricingTier, mode (block/limit), blocked, and limited. errors[] lists anything that could not be collected (a bad link, an unreachable page) without failing the run.


Webhooks

Records are always written to the run's dataset first. Setting webhookUrl adds a second, real-time delivery channel: each record is POSTed to your endpoint the moment it is collected — ideal for pushing leads into a CRM or database while the run is still working.

SettingValue
webhookUrlYour HTTPS endpoint. Leave empty for dataset-only delivery.
webhookFormatjson — the full record object. slack — a Slack-ready message payload.

JSON payload (abridged):

{
"featureType": "search",
"title": "Sport Clips Haircuts of Downtown Boise",
"category": "Hair salon",
"phone": "(208) 345-1823",
"website": "https://sportclips.com/us-id-boise-id106",
"emails": ["info@example.com"],
"rating": 3.5,
"reviewCount": 118,
"address": "1749 W State St, Boise, ID 83702",
"bingUrl": "https://www.bing.com/maps?q=...",
"scrapedAt": "2026-09-22T01:28:35.167Z"
}

Slack payload (webhookFormat: "slack") — POST this to a Slack incoming webhook and every lead appears in your channel:

{
"text": ":round_pushpin: *Sport Clips Haircuts of Downtown Boise*\n*Category:* Hair salon • *Rating:* 3.5\n*Phone:* (208) 345-1823\n*Website:* https://sportclips.com/us-id-boise-id106\n1749 W State St, Boise, ID 83702\n<https://www.bing.com/maps?q=...|View on Bing Maps>"
}

Delivery semantics

  • Best-effort and non-blocking. A failed webhook never stops the run, never delays the dataset, and never loses a record.
  • Retried once on transport errors before the record is counted as failed.
  • Delivery is reported. The run summary carries webhooksDelivered and webhooksFailed, and the log prints a single line, e.g. Webhook: 42 record(s) delivered in real time. or Webhook: 40 delivered, 2 failed — every record is still saved in this run's dataset.
  • Authenticating your endpoint. There is no separate header field: put a token in the URL (https://your-api.com/leads?token=SECRET) — it is sent with every POST.
  • Ordering. Records are delivered in collection order, but treat delivery as at-least-once: deduplicate on placeId in your receiver.
  • Free-plan runs deliver only their capped sample (2 businesses by default, or nothing when the owner sets FREE_TIER_MODE=block).

Webhooks are optional. If you would rather pull data after the run, use the dataset via the Apify API or an Apify integration instead.


API usage

Run via the Apify API

curl -X POST "https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"searchTasks": [
{ "query": "coffee shops", "location": "Seattle, WA", "placesPerQuery": 50 },
{ "query": "bakeries", "location": "Portland, OR", "placesPerQuery": 50 }
],
"minRating": 4,
"requirePhone": true,
"fetchEmails": true,
"maxItems": 500
}'

Read the results

# JSON
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json" -o results.json
# CSV
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=csv" -o results.csv

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('YOUR_ACTOR_ID').call({
searchTasks: [{ query: 'plumbers', location: 'Austin, TX', placesPerQuery: 50 }],
requirePhone: true,
fetchEmails: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);

Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("YOUR_ACTOR_ID").call(run_input={
"searchTasks": [{"query": "lawyers", "location": "Chicago, IL", "placesPerQuery": 50}],
"minRating": 4,
"fetchEmails": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item.get("phone"), item.get("emails"))

LLM & MCP integration

The output is JSON-Lines-friendly structured data — ideal for ChatGPT, Claude, Gemini, LangChain, LlamaIndex, and custom agents.

  1. Run the Actor with the features you need.
  2. Fetch dataset items via the Apify API or export JSON/CSV.
  3. Pass the records to your model with a system prompt, or index them into a vector store.

Apify MCP (Model Context Protocol)

Use the Apify MCP server so AI assistants can run this Actor from natural-language instructions, read the results in chat, and chain it with other Actors.

User: "Find 40 highly rated dentists in Austin that have a phone number and a website, then draft an intro email for each."
→ MCP runs the Actor with searchTasks=[{ query: "dentists", location: "Austin, TX" }],
minRating=4, requirePhone=true
→ MCP reads the dataset
→ LLM segments the list, scores it, and drafts outreach

Performance & cost tips

  • Start small. Run one task with placesPerQuery: 10 to confirm the shape of the output before launching a large job.
  • Use maxItems as your budget guard. The run stops the moment the cap is reached.
  • fetchPlaceDetails adds a small amount of extra work per business. It is worth it for address breakdown and opening hours — turn it off if you only need listing counts and contact fields.
  • fetchEmails is the heavier option — it looks up each business's own website, so allow more time. Pair it with requireWebsite to avoid wasted lookups, and enable it only when you need contactability.
  • Split very large jobs. Several medium runs (one metro each) are more resilient and easier to debug than one enormous run.
  • Schedule repeat snapshots. placeId is stable, so you can diff runs to find new, changed, or closed businesses.
  • Search first, then enrich by URL. Use search to build a list, then feed the specific links you care about back in through Scrape by URL for targeted enrichment.

Proxy & geo

An Apify residential US proxy is enabled by default, because local business results vary by location and IP reputation. Change the country in Proxy settings if you are collecting outside the US, or supply your own proxy URLs.

country and language also influence the locale of names and addresses — set both when collecting outside the US (for example de / de with a German proxy country).


FAQ

Do I need a Bing account or API key? No. The Actor collects publicly available local business listing data. There is nothing for you to configure beyond the input.

Why did my free-plan run only return 2 businesses? Because this is a paid Actor: free accounts receive a free sample of 2 businesses so you can judge the data quality, along with a reminder to upgrade. Paid plans return the full dataset you asked for — nothing else about the run changes. (The owner can switch the sample off entirely with FREE_TIER_MODE=block, in which case a free run exports nothing and says so in the log.)

Why are some fields null? Not every listing exposes every detail. Most businesses have phone, website, rating, and hours, but small or new listings may be missing them. Rows are always exported, and enrichment fills in as much as the source has.

Why is there a ratingSource field? Bing aggregates ratings from third-party directories, so a rating may be attributed to Yelp, Tripadvisor, or Bing itself. We preserve the source rather than hiding it.

How do I get emails for the businesses? Set fetchEmails: true. Emails and social profiles are added as emails[] and socials[].

Can I scrape specific businesses I already have links for? Yes — paste them into Scrape by URL. Each link returns the same field-rich record. If a link points at one branch of a multi-location brand, check linkMatch: business_name means Bing resolved the brand by name and the returned address may be a different branch than the one in your link.

Can the same business appear twice in one run? No. Rows are deduplicated by placeId across search, nearby, and links.

How do I get only businesses within a few kilometres of a point? Add latitude, longitude and radiusMeters to a search task. Only businesses inside that circle are exported, each with distanceMeters. Both coordinates are required — the run tells you clearly if they are missing, because we never guess a centre from a place name.

Why did my radius search return far fewer businesses than I asked for? Because a radius can only filter what the source already returns for that query — it cannot discover businesses the source does not return. Combine a small radius with a tight location (a postcode or neighbourhood rather than a whole city) and a generous placesPerQuery/maxPagesPerQuery so there are enough candidates to filter. The log shows exactly how many were excluded.

Can I target a neighbourhood or a ZIP code instead of a whole city? Yes — put it in the task's location: "downtown Austin" or "78701". Postcodes are the most precise text option (in a measured test, plumbers in 78701 returned results clustered within ~7 km of downtown, versus ~25 km for the city name).

Can I get results in another language or country? Yes — set language and country (e.g. de / de) and match the proxy country.

My run hit the spending limit. That is Apify's per-run spending limit. The Actor stops collecting and exits gracefully so you are not charged for work it did not finish; the run summary sets spendingLimitReached: true.

Can I receive results in real time instead of downloading them? Yes — set webhookUrl and every record is POSTed to your endpoint as it is collected. See Webhooks.


This Actor collects publicly available business listing information. You are responsible for how you use the data, including compliance with applicable data-protection and marketing regulations in your jurisdiction.


Support

Open an issue from the Actor's Issues tab with the run ID and the input you used, and we will take a look.