# GBP Local Pack Rank Tracker (UK Postcode-Level) (`conceivable_extension/gbp-local-pack-rank-tracker`) Actor

Tracks a business's position in the Google local 3-pack and organic local results for a given keyword, measured from specific UK postcodes rather than city-level. From £0.006 per real check.

- **URL**: https://apify.com/conceivable\_extension/gbp-local-pack-rank-tracker.md
- **Developed by:** [joseph fadero](https://apify.com/conceivable_extension) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 local pack check in packs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Business Profile + Local Pack Rank Tracker (UK Postcode-Level)

Tracks a business's position in the Google local 3-pack and organic local results for a given keyword — measured from specific UK postcodes, not just city-level. From £0.006 per real check.

### Why postcode-level

Google's local pack is hyper-local: a business ranked #1 from one street can be invisible three miles away. Most rank trackers only support city or region-level location targeting. This actor geocodes real UK postcodes (via postcodes.io) to precise lat/long coordinates and uses those to geolocate the underlying Google search, so you see exactly what a customer at that postcode sees.

### How it works

1. **Postcode → lat/long**: each postcode (full, e.g. `CM23 2AB`, or outward-only, e.g. `CM23`) is geocoded via [postcodes.io](https://postcodes.io) — a free, no-key, real UK postcode API.
2. **Geolocated Google search**: for each keyword × postcode pair, the actor calls Apify's own `apify/google-search-scraper` via `Actor.call()`, passing a `locationUule` parameter built from the postcode's exact lat/long (Google's own UULE geolocation encoding) — not just a country/region string.
3. **Local pack + organic parsing**: parses both the local 3-pack (`localResults`) and organic results (`organicResults`) from the sub-actor's real dataset output.
4. **Fuzzy business-name matching**: matches `businessName` against every pack/organic result name, case-insensitively and tolerant of minor punctuation, `&`/`and`, legal suffixes (Ltd/Limited), and trailing branch qualifiers.
5. **"No local pack shown" is a valid result** — not an error. Many keyword×postcode combinations genuinely show no map pack.

### Inputs

| Field | Default | Description |
|-------|---------|-------------|
| `businessName` | `Acme Plumbing` | Business name to track (fuzzy-matched) |
| `keywords` | `["emergency plumber"]` | Local search keywords to check |
| `postcodes` | `["CM23 2AB"]` | UK postcodes (full or outward code) to search from |
| `searchRadius` | `5000` | Meters — **advisory only**. Google's UULE geolocation determines the actual geolocated viewpoint; this radius is not enforced by the underlying search API. Recorded on each output row for your own reference. |

### Output fields (per keyword × postcode)

| Field | Description |
|-------|-------------|
| `keyword` | The keyword checked |
| `postcode` | The postcode searched from |
| `searchRadius` | The advisory radius passed in input |
| `localPackShown` | Whether Google showed a local 3-pack for this query at all |
| `localPackPosition` | 1-3 if the business is in the pack, else `null` |
| `organicPosition` | Organic ranking position, or `null` if not found in scraped results |
| `competitorsInPack` | Array of `{name, position}` for every other business in the pack |
| `timestamp` | ISO timestamp of the check |

### Pricing (Pay-Per-Event)

| Event | Price | When charged |
|-------|-------|---------------|
| Actor Start | $0.05 | Once per run (built-in) |
| Organic-Only Check | $0.003 | Query run, no local pack shown for that keyword×postcode |
| Local Pack Check Not In Pack | $0.006 | Pack shown, tracked business absent from it |
| **Local Pack Check In Pack** (primary) | $0.01 | Pack shown, tracked business ranked 1st-3rd |
| Competitor Snapshot | $0.001 | Per additional competitor captured in the pack alongside the tracked business |

### Notes

- Business-name matching is intentionally conservative-but-tolerant: it normalizes case, punctuation, `&`/"and", and common legal suffixes, and allows either name to contain the other (so "Acme Plumbing" matches "Acme Plumbing - Bishop's Stortford" branch listings).
- Uses the same `Actor.call()` sub-actor pattern already proven in this account's `serp-ai-visibility-tracker`, including its fix for the sub-actor's lowercase `countryCode` enum and the requirement to pass `APIFY_TOKEN` explicitly to `ApifyClient` (it is not read from the environment automatically).

# Actor input Schema

## `businessName` (type: `string`):

The exact (or near-exact) name of the business you want to track in the Google local 3-pack and organic local results. Matching is case-insensitive and tolerant of minor punctuation differences.

## `keywords` (type: `array`):

Local search keywords to check, e.g. 'emergency plumber' or 'boiler repair near me'. One local pack + organic check is run per keyword × postcode combination.

## `postcodes` (type: `array`):

UK postcodes to search from — full (e.g. 'CM23 2AB') or outward code only (e.g. 'CM23'). Each is geocoded via postcodes.io to a precise lat/long used to geolocate the Google search.

## `searchRadius` (type: `integer`):

Advisory context field only, in meters. Google's search geolocation (via the UULE parameter derived from the postcode's lat/long) determines the actual geolocated viewpoint — this radius is NOT enforced by the underlying search API and is recorded for your own reference/reporting purposes only.

## Actor input object example

```json
{
  "businessName": "Acme Plumbing",
  "keywords": [
    "emergency plumber"
  ],
  "postcodes": [
    "CM23 2AB"
  ],
  "searchRadius": 5000
}
```

# Actor output Schema

## `resultsDatasetUrl` (type: `string`):

Dataset of local pack / organic rank check records produced by this run.

# 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 = {
    "businessName": "Acme Plumbing",
    "keywords": [
        "emergency plumber"
    ],
    "postcodes": [
        "CM23 2AB"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("conceivable_extension/gbp-local-pack-rank-tracker").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 = {
    "businessName": "Acme Plumbing",
    "keywords": ["emergency plumber"],
    "postcodes": ["CM23 2AB"],
}

# Run the Actor and wait for it to finish
run = client.actor("conceivable_extension/gbp-local-pack-rank-tracker").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 '{
  "businessName": "Acme Plumbing",
  "keywords": [
    "emergency plumber"
  ],
  "postcodes": [
    "CM23 2AB"
  ]
}' |
apify call conceivable_extension/gbp-local-pack-rank-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,conceivable_extension/gbp-local-pack-rank-tracker"
        }
    }
}
```

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/nWYo5QcIa4NovZa8O/builds/3fKIMd61YijgHxxLa/openapi.json
