# Apple Maps Business Listings Scraper (`automation-lab/apple-maps-business-listings-scraper`) Actor

Search Apple Maps by business category, keyword, location, coordinates, or place URL. Export stable place IDs, names, categories, addresses, phones, websites, coordinates, and source URLs for recurring lead and directory refreshes.

- **URL**: https://apify.com/automation-lab/apple-maps-business-listings-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.54 / 1,000 business listing extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Apple Maps Business Listings Scraper

Collect public **Apple Maps business listings** by category, keyword, city, address, or coordinates. The Actor exports stable place IDs, business names, categories, addresses, public phone numbers and websites, coordinates, and canonical Apple Maps URLs to a structured dataset.

Use it to build a local lead list, refresh a directory, verify place identities, or feed public maps data into a spreadsheet, database, CRM, or scheduled Apify workflow.

### What does Apple Maps Business Listings Scraper do?

The Actor turns local search intent into reusable business records.

It supports three practical input routes:

- search one or more categories or keywords around a named location;
- center searches on exact latitude and longitude coordinates;
- resolve supplied `maps.apple.com` search or place URLs.

Each run creates a fresh public Apple MapKit session, searches structured Apple Maps data, normalizes the fields, removes duplicate place IDs, and writes accepted records to the default dataset.

No Apple account is required. The Actor does not ask for private credentials and does not use a browser or a paid residential proxy by default.

### Who is it for?

#### Local lead generation teams

Search categories such as dentists, gyms, cafes, agencies, or coworking spaces in a target market. Export public phone, website, and address fields when Apple Maps exposes them.

#### Directory and marketplace operators

Use stable `placeId` values to reconcile recurring runs and refresh business identity or location fields in an existing catalog.

#### Market researchers

Collect category presence and geographic coordinates for a bounded city or coordinate-centered sample.

#### Data engineers

Schedule runs, consume the dataset API, and load normalized records into a warehouse or enrichment pipeline.

#### Developers and AI agents

Call the Actor through the Apify API or MCP instead of implementing Apple MapKit session bootstrap and response normalization themselves.

### Why use this maps scraper?

- **Stable identity:** every accepted row includes an Apple Maps MUID or result ID as `placeId`.
- **Useful lead fields:** names, categories, formatted addresses, phones, websites, and coordinates are normalized into predictable keys.
- **Multiple searches per run:** submit several categories for the same market.
- **Named or exact geography:** use a location string or latitude/longitude.
- **Source traceability:** keep the canonical `appleMapsUrl`, original `sourceInput`, search term, and collection timestamp.
- **Bounded collection:** per-search and global limits control volume and cost.
- **No silent challenge success:** malformed input, unresolved locations, invalid structured responses, and exhausted upstream retries fail visibly.

This Actor focuses on reusable listing identity and contact/location fields. It does not claim to return ratings, reviews, photos, opening hours, or complete coverage when those fields are not present in the public search response.

### What Apple Maps data can I extract?

| Field | Meaning |
| --- | --- |
| `placeId` | Stable Apple Maps place identifier, normally the MUID |
| `appleMapsId` | MapKit search result identifier |
| `name` | Public business or place name |
| `category` | Apple Maps point-of-interest category |
| `address` | Combined formatted address |
| `addressLines` | Source address split into lines |
| `city` | Locality or city |
| `state` | Administrative region name or code |
| `postalCode` | Postal or ZIP code |
| `country`, `countryCode` | Country fields from Apple Maps |
| `phone` | Public telephone number when available |
| `website` | Public business website when available |
| `latitude`, `longitude` | Place coordinates in decimal degrees |
| `appleMapsUrl` | Canonical public Apple Maps place URL |
| `searchTerm` | Keyword or place name used for lookup |
| `requestedLocation` | Original location text, when supplied |
| `sourceInput` | Keyword or Apple Maps URL that produced the row |
| `scrapedAt` | UTC collection timestamp |

Optional fields are omitted when Apple Maps does not provide them. Do not interpret a missing phone or website as proof that the business has none.

### How to scrape Apple Maps business listings

1. Open the Actor input page.
2. Add one or more values to **Business categories or keywords**.
3. Enter a city, neighborhood, postal code, or address in **Location**.
4. Alternatively, provide exact **Coordinates** or one or more **Apple Maps URLs**.
5. Select `countryCode` and `language` appropriate for the market.
6. Set `maxResultsPerSearch` and `maxItems` to bound the run.
7. Start the run.
8. Open the **Business listings** dataset view.
9. Export JSON, CSV, Excel, XML, or RSS, or read the dataset through the API.

The prefilled example searches for coffee shops in Austin, Texas and is suitable for a first test.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `searchTerms` | string array | prefilled example | Business categories or keywords; up to 50 |
| `location` | string | prefilled example | City, neighborhood, postal code, or address used as the search center |
| `coordinates` | object | none | Exact `latitude` and `longitude`; overrides location for keyword searches |
| `appleMapsUrls` | string array | none | Public Apple Maps search or place URLs; up to 100 |
| `countryCode` | string | `US` | Two-letter ISO country filter |
| `language` | string | `en-US` | Language tag for source labels |
| `maxResultsPerSearch` | integer | `50` | Unique listing limit for each keyword or URL; 1–200 |
| `maxItems` | integer | `200` | Global result cap across the run; 1–1,000 |
| `maxRequestRetries` | integer | `3` | Retry count for network failures, HTTP 429, and HTTP 5xx; 0–6 |

Provide at least one non-empty `searchTerms` or `appleMapsUrls` entry. Coordinates must stay within valid geographic ranges.

### Input examples

#### Search one category by city

```json
{
  "searchTerms": ["coffee shops"],
  "location": "Austin, Texas",
  "countryCode": "US",
  "maxResultsPerSearch": 10,
  "maxItems": 10
}
```

#### Search several categories around coordinates

```json
{
  "searchTerms": ["dentists", "coworking spaces", "fitness studios"],
  "coordinates": {
    "latitude": 30.2672,
    "longitude": -97.7431
  },
  "countryCode": "US",
  "maxResultsPerSearch": 10,
  "maxItems": 30
}
```

#### Resolve an Apple Maps place URL

```json
{
  "appleMapsUrls": [
    "https://maps.apple.com/place?q=Daydreamer%20Coffee&auid=1585039323930825247&ll=30.2592149,-97.7389039"
  ],
  "countryCode": "US",
  "maxResultsPerSearch": 1,
  "maxItems": 1
}
```

### Output example

This shortened record comes from the current Austin coffee-shop workflow:

```json
{
  "placeId": "1585039323930825247",
  "appleMapsId": "I15FF30DE01EC121F",
  "name": "Daydreamer Coffee",
  "category": "Cafe",
  "address": "80 Rainey St, Austin, TX 78701, United States",
  "city": "Austin",
  "state": "TX",
  "postalCode": "78701",
  "countryCode": "US",
  "phone": "+17404000238",
  "website": "https://www.daydreamer.coffee/",
  "latitude": 30.2592149,
  "longitude": -97.7389039,
  "appleMapsUrl": "https://maps.apple.com/place?q=Daydreamer%20Coffee&auid=1585039323930825247&ll=30.2592149,-97.7389039",
  "searchTerm": "coffee shops",
  "requestedLocation": "Austin, Texas",
  "sourceInput": "coffee shops",
  "scrapedAt": "2026-08-26T20:09:06.558Z"
}
```

Public source values can change between runs. The schema remains stable while optional properties may be absent.

### How location and coverage work

A named `location` is first resolved to coordinates through Apple Maps. Keyword searches are then centered on that point.

For limits above a single response, the Actor checks a bounded grid of nearby centers and deduplicates results by stable place ID. This improves useful local coverage, but it is not a guarantee that every business in a city or radius will be returned. Apple controls ranking, source availability, and response size.

Coordinate searches are useful when exact repeatability matters. Named locations are easier for operators and scheduled Tasks.

A `countryCode` limits results to one country. Choose the code that matches the search market.

### How much does it cost to collect Apple Maps business listings?

The Actor uses pay-per-event pricing:

- one `start` event at **$0.001 per run**;
- one `item` event for each accepted business listing written to the dataset.

The active per-listing tiers are:

| Apify plan tier | Price per accepted listing |
| --- | ---: |
| FREE | $0.002944 |
| BRONZE | $0.00256 |
| SILVER | $0.0019968 |
| GOLD | $0.001536 |
| PLATINUM | $0.001024 |
| DIAMOND | $0.0007168 |

At the BRONZE tier, a 10-row test costs up to **$0.0266** ($0.001 start + 10 × $0.00256). A three-category refresh capped at 30 rows costs up to **$0.0778**. A 100-row run costs up to **$0.257**.

Your maximum is predictable from the selected result limits: one run start plus at most `maxItems` item events. Duplicate, rejected, empty, and failed records do not produce item events.

Set a platform maximum total charge if you need an additional hard billing guard. Higher Apify plans receive the lower per-item tier prices shown above.

### Recurring lead and directory refresh workflow

1. Create a Task with categories, geography, and stable limits.
2. Run it once and store `placeId` as the source key in your system.
3. Schedule the Task daily, weekly, or monthly.
4. Export or consume the latest default dataset.
5. Join current rows to prior rows by `placeId`.
6. Treat new IDs as newly observed listings and compare supported fields for changes.

The Actor emits current snapshots; it does not maintain historical state or send change alerts itself. Use Apify schedules, webhooks, dataset integrations, or your own warehouse logic for comparison and notification.

### Integrations and exports

You can connect results to:

- Google Sheets or Microsoft Excel for review;
- Airtable or a business directory database;
- HubSpot, Salesforce, or another CRM after applying your own contact rules;
- Zapier or Make through Apify integrations and webhooks;
- Amazon S3, Google Cloud Storage, or a data warehouse;
- n8n, custom Node.js/Python jobs, or an AI agent through the API.

Every run uses the default dataset, so standard Apify dataset export endpoints work without Actor-specific parsing.

### Run through the Apify API

Replace `<APIFY_TOKEN>` with your token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~apple-maps-business-listings-scraper/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms":["dentists"],"location":"Austin, Texas","maxItems":20}'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/apple-maps-business-listings-scraper').call({
  searchTerms: ['dentists'],
  location: 'Austin, Texas',
  countryCode: 'US',
  maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("automation-lab/apple-maps-business-listings-scraper").call(run_input={
    "searchTerms": ["dentists"],
    "location": "Austin, Texas",
    "countryCode": "US",
    "maxItems": 20,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI agents

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/apple-maps-business-listings-scraper"
```

#### Claude Desktop

Add this server to the `mcpServers` object in Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/apple-maps-business-listings-scraper"
    }
  }
}
```

#### Cursor

Open **Settings → Tools & MCP**, add an HTTP MCP server, and use the same Actor-specific URL shown above.

#### VS Code

Add the same HTTP server URL through your MCP-compatible VS Code extension or workspace MCP configuration, then enable the Actor tool for the current chat.

Example prompts:

- “Find up to 20 dentists on Apple Maps near Austin, Texas and return place IDs, websites, phones, and addresses.”
- “Resolve this Apple Maps place URL and give me the stable place ID and coordinates.”
- “Run three local categories around latitude 30.2672, longitude -97.7431 and group the dataset by category.”

Review generated inputs and public contact data before using them in downstream outreach.

### Reliability, retries, and failure behavior

The Actor creates a fresh temporary public MapKit session for every run. It retries only transient network failures, rate limits, and upstream server errors with bounded exponential backoff.

The run fails instead of returning misleading empty success when:

- neither search terms nor Apple Maps URLs are supplied;
- coordinates or country codes are malformed;
- a named location cannot be resolved;
- the public session bootstrap no longer returns a token;
- the structured endpoint returns an unexpected shape;
- retries are exhausted.

A valid search with no matching points of interest completes with zero rows. Check both run status and dataset item count in automated workflows.

### Limits and responsible expectations

- Search results are ranked and selected by Apple; the Actor does not guarantee exhaustive city or radius coverage.
- Public phone and website fields are optional.
- The Actor does not fetch ratings, reviews, photos, amenities, or opening hours.
- URL resolution requires a URL with a usable `q` or `query` value. Exact place matching additionally uses `auid` when present.
- Apple may change public responses, categories, rankings, or session behavior.
- `maxResultsPerSearch` is capped at 200 and `maxItems` at 1,000.
- There is no automatic residential proxy fallback, avoiding hidden proxy transfer cost.

Start with a small limit, inspect the output, and then schedule or scale the workflow.

### Is scraping Apple Maps legal?

This Actor collects publicly accessible business listing data. Whether a particular use is lawful depends on your jurisdiction, purpose, data handling, and contractual obligations.

Use the Actor responsibly:

- collect only data you have a legitimate reason to process;
- respect applicable laws, source terms, and database rights;
- avoid sensitive-person profiling or prohibited discrimination;
- follow marketing, privacy, and do-not-contact rules before outreach;
- secure exported datasets and delete them when no longer needed;
- do not use the Actor to overload or disrupt the source.

This documentation is not legal advice.

### Troubleshooting

#### The run says I must provide a search term or URL

Add at least one non-empty value to `searchTerms` or `appleMapsUrls`. An empty array does not create a search.

#### My location cannot be resolved

Use a more specific city, region, postal code, or address, confirm `countryCode`, or provide exact coordinates.

#### A business has no phone or website

Those fields are optional and are emitted only when present in the public Apple Maps search response. Try the canonical `appleMapsUrl` to review the current source listing.

#### I received fewer rows than the limit

Limits are maximums, not guarantees. Ranking, source response size, deduplication, exact URL filtering, and naturally sparse categories can all reduce the final count.

#### Should I enable a proxy?

No proxy input is needed. The Actor uses the current direct public structured route and intentionally avoids an unmeasured paid fallback.

### Frequently asked questions

#### Can I search multiple categories in one run?

Yes. Add up to 50 `searchTerms`. `maxResultsPerSearch` applies to each and `maxItems` caps the entire run.

#### Can I search by coordinates?

Yes. Supply both latitude and longitude in `coordinates`. They override `location` for keyword searches.

#### Can I scrape an Apple Maps URL?

Yes. Public search and place URLs on `maps.apple.com` are supported when they include `q` or `query`. Place URLs with `auid` are filtered to that requested place ID.

#### Does the Actor monitor changes?

It produces current snapshots suitable for scheduled comparison. It does not store history or send alerts by itself.

#### Are duplicate businesses removed?

Yes. Records are deduplicated by stable MUID/result ID across the whole run.

#### Does it require an Apple account?

No. It uses the anonymous public Apple Maps web and MapKit data flow.

### Related Automation Lab Actors

- [Bing Maps Places Scraper](https://apify.com/automation-lab/bing-maps-places-scraper) — collect a comparable local-place dataset from Bing Maps.
- [Foursquare Locations Scraper](https://apify.com/automation-lab/foursquare-locations-scraper) — collect Foursquare location and venue records.
- [Naver Map Local Business Scraper](https://apify.com/automation-lab/naver-map-local-business-scraper) — target Naver Map business data for supported markets.

Choose one source when its place identity is your system of record, or run several source-specific Actors and reconcile records in your own pipeline.

### Support

If a valid public workflow stops working, open an issue from the Actor page and include:

- a redacted copy of the input;
- run ID;
- expected result;
- observed error or missing field;
- whether the same query currently works on the public Apple Maps website.

Do not include private credentials, customer data, or unrelated personal information.

# Actor input Schema

## `searchTerms` (type: `array`):

One or more searches, such as coffee shops, dentists, or coworking spaces.

## `location` (type: `string`):

City, neighborhood, postal code, or address used to center searches. Optional when coordinates or Apple Maps URLs are supplied.

## `coordinates` (type: `object`):

Optional exact search center. Overrides the location for keyword searches.

## `appleMapsUrls` (type: `array`):

Optional maps.apple.com search or place URLs. Place URLs containing q, auid, and ll are resolved to the matching stable place record.

## `countryCode` (type: `string`):

Two-letter ISO country code used to limit Apple Maps results.

## `language` (type: `string`):

Language tag for returned labels, such as en-US or de-DE.

## `maxResultsPerSearch` (type: `integer`):

Maximum unique listings collected for each keyword or supplied URL.

## `maxItems` (type: `integer`):

Global cap across all searches and URLs.

## `maxRequestRetries` (type: `integer`):

Retries for temporary network, rate-limit, and upstream server errors.

## Actor input object example

```json
{
  "searchTerms": [
    "coffee shops"
  ],
  "location": "Austin, Texas",
  "countryCode": "US",
  "language": "en-US",
  "maxResultsPerSearch": 10,
  "maxItems": 20,
  "maxRequestRetries": 3
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset containing all collected Apple Maps business listings.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "coffee shops"
    ],
    "location": "Austin, Texas",
    "countryCode": "US",
    "language": "en-US",
    "maxResultsPerSearch": 10,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/apple-maps-business-listings-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": ["coffee shops"],
    "location": "Austin, Texas",
    "countryCode": "US",
    "language": "en-US",
    "maxResultsPerSearch": 10,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/apple-maps-business-listings-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "coffee shops"
  ],
  "location": "Austin, Texas",
  "countryCode": "US",
  "language": "en-US",
  "maxResultsPerSearch": 10,
  "maxItems": 20
}' |
apify call automation-lab/apple-maps-business-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/apple-maps-business-listings-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/CCrO6Jb3TYZgVlde4/builds/AzSJbYQ1TV3OxkW6z/openapi.json
