# Google Maps Postcode Filter — ZIP & Postal Territories (`mrtronson/google-maps-postcode-filter`) Actor

Filter existing Google Maps datasets by ZIP code or postcode prefix, including T6R\* and SW1A\*. Exclude subareas, restrict countries, and download matching leads plus a row-by-row audit. No rescraping. $0.05 per completed report, up to 10,000 rows.

- **URL**: https://apify.com/mrtronson/google-maps-postcode-filter.md
- **Developed by:** [Typed Diff](https://apify.com/mrtronson) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.05 / completed filtering report

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

### Filter Google Maps leads by ZIP code or postcode prefix

**Keep only the businesses in your postal territory.** Select an existing Apify dataset, enter codes such as `T6R*`, `SW1A*` or `02108`, and download the matching leads plus an audit of every rejected row. Existing Google Maps scraper output works with the default `postalCode` field.

Run the included synthetic example first: it keeps one row, rejects one excluded postcode, rejects one outside the territory and identifies one missing postcode. Replace the example with your own completed dataset to process real leads. This Actor processes data already collected; it does not scrape Google Maps or pay another Actor to collect it.

### Why use it?

Prepare territory-specific CRM imports without spreadsheet formulas, repeated filtering or another scraping run. Combine multiple postcode prefixes, subtract exact postcodes or smaller prefixes, and see why each record passed or failed. An optional country filter prevents identical postal codes in different countries from being mixed.

Use the Actor through the Apify API, scheduled tasks or integrations after your scraper finishes. All processing stays in your Apify run. No external enrichment service, LLM, geocoder or API key is required.

### How to use it

1. Select a completed source dataset in **Dataset to filter**. This overrides the example rows.
2. Replace **Include postcodes** with your exact codes or prefixes ending in `*`.
3. Optionally add exclusions and two-letter country codes.
4. Run and open **Kept leads — CSV** or **Kept leads — JSON** in the output.
5. Check the summary and audit before importing into your CRM.

### Input

```json
{
  "includePostcodes": ["T6R*"],
  "excludePostcodes": ["T6R 0A1"],
  "countryCodes": ["CA"],
  "data": [
    {"title":"Synthetic Example","postalCode":"t6r 2v4","countryCode":"CA"}
  ]
}
```

For real data, set `datasetId` instead of `data`. Change `postcodeField` or `countryField` for other scraper schemas; dotted paths such as `address.postcode` are supported. The default fields are `postalCode` and `countryCode`.

Spaces, hyphens and letter case are normalized. `T6R*` means any normalized code starting with T6R. `T6R 2V4` is an exact match. Wildcards anywhere except the end are rejected. Exclusions always win. ZIP+4 requires an explicit prefix if the extension should match, for example `02108*`.

### Output

`KEPT.json` contains matching records. Each has `sourceRow`, `status`, `title`, `placeId`, `postalCode`, `normalizedPostcode`, `countryCode`, `matchedPatterns`, `excludedPatterns`, `website`, `phone`, and the complete original `record`.

`AUDIT.json` contains every input row with its decision. CSV versions of both files are provided; potentially active spreadsheet cells are escaped. `SUMMARY` and the default dataset contain row counts and rejection totals. An empty result is valid and still produces a completed report and CSV headers.

| Status | Meaning |
|---|---|
| kept | Included and not excluded |
| excluded\_postcode | Matched an exclusion |
| outside\_postcode\_selection | No inclusion matched |
| country\_not\_allowed | Country did not match the requested countries |
| missing\_or\_invalid\_postcode | No usable text postcode; numeric codes are not guessed |

### Pricing

**$0.05 per completed filtering report**, including up to 10,000 input rows and all four exports. A report with zero matching leads is also a completed report. Invalid input does not trigger the custom event. Check the Pricing tab for the active rate and any platform charges. Running your own Actor for development is not evidence of a customer sale.

### Limits and support

Use completed datasets containing at most 10,000 rows and 10 MiB. Every page is read; oversize or changing sources fail instead of silently returning a partial report. The Actor reads only the selected dataset and its own run storage. Inline data are supported for API and one-off use.

Postcode matching uses the supplied data. It does not verify postal validity, street addresses, service areas or geographic boundaries, and does not deduplicate businesses. Preserve leading zeros by storing postcodes as text. Missing country values are rejected when country filtering is enabled. A selected dataset takes precedence over the sample rows, but never changes your filter settings.

Report reproducible problems through the Issues tab with a small synthetic example. Do not include API keys or private lead data in public issues.

# Actor input Schema

## `datasetId` (type: `string`):

Select a completed Google Maps dataset. Overrides the sample rows below. Up to 10,000 rows / 10 MiB.

## `includePostcodes` (type: `array`):

Required. Exact code or trailing *, e.g. T6R*, SW1A\*, 02108. Any inclusion can match.

## `excludePostcodes` (type: `array`):

Exclusions override inclusions. Remove the example exclusion when using your data.

## `countryCodes` (type: `array`):

Two-letter codes, e.g. CA, GB, US. Empty permits all countries. Change the example CA for your territory.

## `postcodeField` (type: `string`):

Field containing a text postcode; dotted paths supported. Numeric postcodes are rejected to protect leading zeros.

## `countryField` (type: `string`):

Field with two-letter country codes. Used only when country filtering is enabled.

## `data` (type: `array`):

Synthetic test rows. Ignored when a dataset is selected. Replace with your own rows for inline processing.

## Actor input object example

```json
{
  "includePostcodes": [
    "T6R*"
  ],
  "excludePostcodes": [
    "T6R 0A1"
  ],
  "countryCodes": [
    "CA"
  ],
  "postcodeField": "postalCode",
  "countryField": "countryCode",
  "data": [
    {
      "title": "Synthetic kept lead",
      "postalCode": "t6r 2v4",
      "countryCode": "CA"
    },
    {
      "title": "Synthetic excluded lead",
      "postalCode": "T6R 0A1",
      "countryCode": "CA"
    },
    {
      "title": "Synthetic outside lead",
      "postalCode": "T5J 0N3",
      "countryCode": "CA"
    },
    {
      "title": "Synthetic missing postcode",
      "countryCode": "CA"
    }
  ]
}
```

# Actor output Schema

## `keptCsv` (type: `string`):

No description

## `keptJson` (type: `string`):

No description

## `auditCsv` (type: `string`):

No description

## `auditJson` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "includePostcodes": [
        "T6R*"
    ],
    "excludePostcodes": [
        "T6R 0A1"
    ],
    "countryCodes": [
        "CA"
    ],
    "data": [
        {
            "title": "Synthetic kept lead",
            "postalCode": "t6r 2v4",
            "countryCode": "CA"
        },
        {
            "title": "Synthetic excluded lead",
            "postalCode": "T6R 0A1",
            "countryCode": "CA"
        },
        {
            "title": "Synthetic outside lead",
            "postalCode": "T5J 0N3",
            "countryCode": "CA"
        },
        {
            "title": "Synthetic missing postcode",
            "countryCode": "CA"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrtronson/google-maps-postcode-filter").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 = {
    "includePostcodes": ["T6R*"],
    "excludePostcodes": ["T6R 0A1"],
    "countryCodes": ["CA"],
    "data": [
        {
            "title": "Synthetic kept lead",
            "postalCode": "t6r 2v4",
            "countryCode": "CA",
        },
        {
            "title": "Synthetic excluded lead",
            "postalCode": "T6R 0A1",
            "countryCode": "CA",
        },
        {
            "title": "Synthetic outside lead",
            "postalCode": "T5J 0N3",
            "countryCode": "CA",
        },
        {
            "title": "Synthetic missing postcode",
            "countryCode": "CA",
        },
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("mrtronson/google-maps-postcode-filter").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 '{
  "includePostcodes": [
    "T6R*"
  ],
  "excludePostcodes": [
    "T6R 0A1"
  ],
  "countryCodes": [
    "CA"
  ],
  "data": [
    {
      "title": "Synthetic kept lead",
      "postalCode": "t6r 2v4",
      "countryCode": "CA"
    },
    {
      "title": "Synthetic excluded lead",
      "postalCode": "T6R 0A1",
      "countryCode": "CA"
    },
    {
      "title": "Synthetic outside lead",
      "postalCode": "T5J 0N3",
      "countryCode": "CA"
    },
    {
      "title": "Synthetic missing postcode",
      "countryCode": "CA"
    }
  ]
}' |
apify call mrtronson/google-maps-postcode-filter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrtronson/google-maps-postcode-filter"
        }
    }
}
```

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/hJLS8i4U4vzV5mAH4/builds/SI5l9rZTkqEqHf0q3/openapi.json
