# Google Local Pack Results API (`khadinakbar/google-local-pack-api`) Actor

Return the businesses shown in Google's local pack for each keyword and location snapshot. Results include position, rating, reviews, address, phone, website, Google IDs, verification URL, timestamp, and provider cost. DataForSEO credentials remain owner-managed environment secrets.

- **URL**: https://apify.com/khadinakbar/google-local-pack-api.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** SEO tools, Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 local pack serp snapshots

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Google Local Pack Results API

Get the businesses shown in Google's Local Pack for a keyword and location. Each dataset row is one dated Google SERP snapshot and includes the returned local businesses, their pack position, rating, review count, address, phone, website, Google identifiers, a verification URL, and provider-cost provenance.

It is designed for local SEO agencies, multi-location brands, and automation builders that need a compact record of who Google showed in the Local Pack at a particular point and time.

### Best fit

Use this Actor when the question is: “Which businesses did Google show in the Local Pack for this search here?” It accepts keyword lists and city, country, or coordinate-based locations, then returns one snapshot for every keyword/location combination.

- Start with a precise coordinate and radius when neighborhood-level variation matters.
- Use `locationCode` or `locationName` for country, city, or regional comparisons.
- Schedule the same input to form a time series of comparable snapshots.
- Read `localPackFound` before treating an empty `localPack` array as a competitor absence: Google displays Local Packs selectively by query and location.

For tracking one known business's position against a target name, domain, CID, or Place ID, use a dedicated local-rank workflow. This Actor instead returns the whole Local Pack block Google displayed.

### What one record means

One dataset record represents **one completed Google organic SERP request for one `query` at one input location**. It is a bounded SERP observation focused on the visible Local Pack; broad Google Maps and Google Local Finder inventories are a separate collection workflow.

The common Google “3-pack” is a Local Pack. The provider can return a different number of businesses or omit the Local Pack block, so the record always includes both `localPackFound` and `localPackSize`.

### Focused standalone workflow

This Actor is designed as a focused standalone workflow when a decision depends on the visible Google Local Pack for a keyword and location. Start with a precise query and location, then pass the returned business identifiers and source snapshots into your reporting, monitoring, or local SEO analysis process.

### Quick start

Use a local-intent query and one precise location:

```json
{
  "queries": ["dentist near me"],
  "locations": [
    {
      "label": "Downtown New York",
      "locationCoordinate": "40.7128,-74.0060,500"
    }
  ],
  "languageCode": "en",
  "device": "desktop",
  "seDomain": "google.com",
  "maxLocalPackResults": 3
}
```

`locationCoordinate` uses `latitude,longitude,radius` in metres. Its radius must be 199–199999 metres. Set exactly one location selector per object:

| Selector | Good for | Example |
| --- | --- | --- |
| `locationCoordinate` | A neighborhood or geo-grid point | `40.7128,-74.0060,500` |
| `locationName` | A named city or region | `New York,New York,United States` |
| `locationCode` | A known DataForSEO location | `2840` |

Duplicate queries and locations are collapsed before requests are made. The maximum is 500 unique query/location snapshots per run.

### Output fields

| Field | Meaning |
| --- | --- |
| `query` | The exact Google search term evaluated. |
| `locationLabel` | Your human-readable location label. |
| `localPackFound` | Whether Google returned a Local Pack block. |
| `localPackSize` | Valid businesses parsed before the output cap. |
| `localPack` | Returned businesses in Local Pack order. |
| `localPack[].position` | The provider's position within the Local Pack. |
| `localPack[].name` | Business name as returned by Google. |
| `localPack[].rating` / `reviewCount` | Public rating signals when Google returned them. |
| `localPack[].address`, `phone`, `website` | Public business information when returned. |
| `localPack[].businessProfileUrl`, `bookingUrl` | Google profile and booking links when returned. |
| `localPack[].distance`, `openStatus`, `serviceOptions` | Public local context parsed from the displayed Local Pack description. |
| `localPack[].cid` / `placeId` | Google identifiers when returned. |
| `checkUrl` | Provider verification URL when available, otherwise a reconstructed Google search URL. |
| `snapshotAt` | When this snapshot was processed. |
| `providerCostUsd` | Cost reported by the SERP provider for that request. |

Example dataset item:

```json
{
  "runId": "abc123",
  "snapshotAt": "ISO-8601 collection timestamp",
  "query": "dentist near me",
  "locationLabel": "Downtown New York",
  "locationCoordinate": "40.7128,-74.0060,500",
  "languageCode": "en",
  "device": "desktop",
  "seDomain": "google.com",
  "localPackFound": true,
  "localPackSize": 3,
  "returnedLocalPackSize": 3,
  "localPack": [
    {
      "position": 1,
      "name": "Example Dental",
      "category": "Dentist",
      "address": "123 Example Street, New York, NY",
      "phone": "+1 212 555 0100",
      "website": "https://example-dental.invalid",
      "domain": "example-dental.invalid",
      "businessProfileUrl": "https://www.google.com/maps?cid=123456789",
      "bookingUrl": null,
      "cid": "123456789",
      "placeId": "ChIJexample",
      "rating": 4.8,
      "reviewCount": 120,
      "latitude": 40.7128,
      "longitude": -74.006,
      "isPaid": false,
      "description": "0.2 mi · 123 Example Street, New York, NY · +1 212 555 0100",
      "distance": "0.2 mi",
      "openStatus": "Open · Closes 6 PM",
      "serviceOptions": ["Onsite services"]
    }
  ],
  "providerNoResults": false,
  "serpItemTypes": ["local_pack", "organic"],
  "provider": "dataforseo",
  "providerCostUsd": 0.01,
  "checkUrl": "https://www.google.com/search?q=dentist+near+me&hl=en",
  "warnings": []
}
```

Fields other than the documented required keys can be absent when Google or the provider does not return them. Preserve `snapshotAt`, the location selectors, and `checkUrl` when comparing datasets across time.

### API call and dataset readback

Run the Actor through the Apify API, then read its default dataset:

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~google-local-pack-api/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": ["dentist near me"],
    "locations": [{"label": "Downtown New York", "locationCoordinate": "40.7128,-74.0060,500"}],
    "languageCode": "en",
    "device": "desktop",
    "maxLocalPackResults": 3
  }'
```

The response includes a run ID. After it completes, export the records:

```bash
curl "https://api.apify.com/v2/actor-runs/RUN_ID/dataset/items?token=$APIFY_TOKEN"
```

For automation, `OUTPUT` is a compact terminal record and `RUN_SUMMARY` includes provider attempts, persisted snapshot count, safe errors, provider cost, and billing diagnostics. Possible outcomes are `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, `UPSTREAM_FAILED`, and `CONFIG_ERROR`.

### Credentials and data provenance

The Actor uses DataForSEO's Google Organic Live Advanced endpoint. DataForSEO credentials are configured only as owner-managed `DATAFORSEO_LOGIN` and `DATAFORSEO_PASSWORD` environment secrets. They are never accepted through the input, stored in the dataset, written to terminal records, or placed in logs.

Every row reports `provider: "dataforseo"`, `providerCostUsd`, and `checkUrl` so a consumer can retain the source and timing of the snapshot. Google SERPs are dynamic; a row states what the configured provider returned for the requested query, device, language, and location at `snapshotAt`.

### Pricing and cost controls

This Actor uses Pay per event plus Apify platform usage. The billable unit is one persisted keyword/location Local Pack snapshot, including an explicit Local-Pack-absent snapshot when Google omits that block. Apify platform compute and any configured proxy usage are additional; see the Actor's live Pricing tab for current event pricing and platform-usage details.

Cost grows with the number of unique query/location pairs. Start with one query and one location to verify that the geography and language match your workflow, then expand in controlled batches. The Actor caps a run at 500 unique snapshots and stops requesting new snapshots if the configured Apify event-charge cap is reached.

### AI Agent and MCP prompt card

> For each keyword in my list, capture the Google Local Pack at these exact coordinate points. Return each business's pack position, name, category, rating, review count, address, phone, website, CID, Place ID, source URL, and collection time. Keep an explicit Local-Pack-absent snapshot when Google omits the block so I can distinguish the SERP result from a missing run.

This is a read-only data collection operation. An agent should supply local-intent queries plus one unambiguous location selector per point, then read the dataset and `RUN_SUMMARY` after processing completes.

### Workflow example

A local SEO analyst wants to compare the visible dentist competitors across several neighborhoods. They provide the same query and coordinate points for each neighborhood, receive one comparable snapshot per point, and group `localPack[].domain`, `rating`, `reviewCount`, and `position` by `snapshotAt`. Repeating the same saved input later yields a time-stamped evidence trail that supports a location-aware visibility review.

### Builder's note

I designed this Actor to return the Google organic SERP's `local_pack` block as its own product surface. That distinction preserves the SERP surface a local SEO workflow evaluates, while keeping each record small enough to compare by query, location, device, and time.

### Responsible use

Use this Actor only for public or otherwise authorized search data, and comply with applicable law, Google terms, DataForSEO terms, and privacy obligations. Treat business contact fields as public business data and handle any personal information appropriately for your use case.

# Actor input Schema

## `queries` (type: `array`):

Local-intent searches to snapshot, such as \['dentist near me', 'emergency dentist']. Each query runs at every supplied location. Provide 1–100 non-empty queries; this Actor does not generate keywords.

## `locations` (type: `array`):

Each location must specify exactly one of locationCode, locationName, or locationCoordinate. Coordinates are best for a precise neighborhood snapshot and must be latitude,longitude,radius in metres. Maximum 25 locations and 500 total query/location snapshots per run.

## `languageCode` (type: `string`):

DataForSEO Google language code, e.g. en or es. Defaults to en; it controls the SERP language, not the location.

## `device` (type: `string`):

Google result layout to request. Local-pack appearance can vary by device.

## `seDomain` (type: `string`):

Optional Google domain such as google.com, google.co.uk, or google.de. Leave blank to let DataForSEO choose a domain for the selected language and location.

## `maxLocalPackResults` (type: `integer`):

Maximum local-pack businesses to return from each Google SERP block. Defaults to 3 to match the common local 3-pack; use up to 20 only when the provider returns more businesses in the local-pack block.

## Actor input object example

```json
{
  "queries": [
    "dentist near me"
  ],
  "locations": [
    {
      "label": "Downtown New York",
      "locationCoordinate": "40.7128,-74.0060,500"
    }
  ],
  "languageCode": "en",
  "device": "desktop",
  "seDomain": "google.com",
  "maxLocalPackResults": 3
}
```

# Actor output Schema

## `localPackSnapshots` (type: `string`):

One processed Google SERP snapshot per keyword/location, containing local-pack businesses or an explicit no-local-pack result.

## `runSummary` (type: `string`):

Detailed terminal summary with per-provider diagnostics, counts, and provider cost.

## `compactOutput` (type: `string`):

Stable terminal result for automation and agents.

# 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 = {
    "queries": [
        "dentist near me"
    ],
    "locations": [
        {
            "label": "Downtown New York",
            "locationCoordinate": "40.7128,-74.0060,500"
        }
    ],
    "languageCode": "en",
    "device": "desktop",
    "seDomain": "google.com",
    "maxLocalPackResults": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/google-local-pack-api").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 = {
    "queries": ["dentist near me"],
    "locations": [{
            "label": "Downtown New York",
            "locationCoordinate": "40.7128,-74.0060,500",
        }],
    "languageCode": "en",
    "device": "desktop",
    "seDomain": "google.com",
    "maxLocalPackResults": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/google-local-pack-api").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 '{
  "queries": [
    "dentist near me"
  ],
  "locations": [
    {
      "label": "Downtown New York",
      "locationCoordinate": "40.7128,-74.0060,500"
    }
  ],
  "languageCode": "en",
  "device": "desktop",
  "seDomain": "google.com",
  "maxLocalPackResults": 3
}' |
apify call khadinakbar/google-local-pack-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/google-local-pack-api"
        }
    }
}

```

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/YpwdWR0SnyI3jTWx6/builds/GY05xlPvMQc9ZW5Z2/openapi.json
