# Waze Places Search Scraper (`romy/waze-places-search-scraper`) Actor

Batch venue search, nearby POI discovery, and reverse geocoding against Waze's internal live protocol — pass an array of point queries, get one dataset row per result. No account or API key needed. Derived from romy/waze-all-in-one-api.

- **URL**: https://apify.com/romy/waze-places-search-scraper.md
- **Developed by:** [Romy](https://apify.com/romy) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.68 / 1,000 place result pusheds

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?

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

### What does Waze Places Search Scraper do?

**Waze Places Search Scraper** runs a batch of point queries — venue search, nearby POI discovery, and/or reverse geocoding — against Waze's internal live protocol, and pushes one dataset row per result. Pass an array of `{operation, lat, lon, ...}` objects in a single run instead of calling one endpoint per point.

It talks directly to the same internal protocol the official [Waze](https://www.waze.com/) Android app uses (`rt.waze.com`), reverse-engineered by live MITM capture against a real device and cross-referenced against the app's own decompiled protobuf schema (see `proto/waze_rt.proto` in the source repo — field names and numbers are the real app's, not guesses). No Waze account, no API key, no scraping setup. Each query opens its own short-lived anonymous session server-side; you never see or manage credentials. This is the places-search slice of [Waze All-in-One API](https://apify.com/romy/waze-all-in-one-api), split out as its own focused batch Actor.

### Why use Waze Places Search Scraper?

- **Batch, not one-call-at-a-time** — mix `search`, `nearby`, and `reverse-geocode` queries for many different points in one Actor run
- **Place search** — the same location-biased venue lookup as the app's search bar
- **Nearby POI discovery** — what's around a point, with real category tags, no text query needed
- **Reverse geocoding** — turn any coordinate into a street address
- **No account needed** — every query authenticates itself
- **Use cases:** logistics/routing risk analysis, points-of-interest datasets, address enrichment, urban mobility research, travel/mapping apps

### How this connects to the parent

[Waze All-in-One API](https://apify.com/romy/waze-all-in-one-api) is an always-on Standby REST API exposing `/search`, `/nearby`, `/reverse-geocode`, plus `/alerts`, `/route`, `/walking-distance`, `/eta-batch`, and `/sos-providers`. This Actor derives from the same three place-query endpoints, but runs as a normal batch Actor: give it an array of point queries as input, get dataset rows out — no HTTP client, no Standby URL, no per-call pricing tab. Use the parent Actor instead if you need on-demand single calls or any of its other endpoints (live traffic alerts, route calculation, ETA, SOS contacts).

### Input

`queries` — required, non-empty array. Each item:

| Field        | Type    | Description                                                                 |
| ------------ | ------- | --------------------------------------------------------------------------- |
| `operation`  | string  | `search` | `nearby` | `reverse-geocode`. Required.                        |
| `lat`        | number  | Latitude, decimal degrees. Required.                                        |
| `lon`        | number  | Longitude, decimal degrees. Required.                                       |
| `query`      | string  | Free-text venue query. Required for `search`.                               |
| `maxResults` | integer | Max results. Default `5` for `search`, `10` for `nearby`. Unused otherwise. |
| `radius`     | integer | Search radius in meters. Default `50`. Only used by `reverse-geocode`.      |

A malformed item (missing/invalid fields for its `operation`) is logged and skipped — it does not fail the whole run.

Example:

```json
{
    "queries": [
        { "operation": "search", "query": "SPBU", "lat": -6.1754, "lon": 106.827, "maxResults": 3 },
        { "operation": "nearby", "lat": -6.175, "lon": 106.827, "maxResults": 3 },
        { "operation": "reverse-geocode", "lat": -6.1954, "lon": 106.8206 }
    ]
}
```

### Output

One dataset row per result item, tagged with the query that produced it. `search` and `nearby` push one row per venue found; `reverse-geocode` pushes exactly one row per query (with `venue: null` if nothing was found).

`search` / `nearby` row (trimmed real example):

```json
{
    "query": { "operation": "search", "query": "SPBU", "lat": -6.1754, "lon": 106.827, "maxResults": 3 },
    "name": "SPBU 34.10401",
    "location": { "x": 106.843635672, "y": -6.184980284 },
    "city": "Jakarta Pusat",
    "country": "ID",
    "address": "Kramat Raya 116 RT 002/09",
    "phone": "+62-21-3106507"
}
```

`reverse-geocode` row:

```json
{
    "query": { "operation": "reverse-geocode", "lat": -6.1954, "lon": 106.8206 },
    "venue": { "street": "Jalan Teluk Betung", "city": "Jakarta Pusat" }
}
```

Venue fields (`name` / `houseNumber` / `street` / `city` / `country` / `address` / `phone`) are as reported — not every field is populated for every result. `location.x` / `location.y` are longitude/latitude in plain decimal degrees, present on `search` and `nearby` results only. `categories` (e.g. `["MUSEUM"]`, `["CAFE"]`) is present on `nearby` results only.

### Known limitations

- **`reverse-geocode` returned empty in some regions during the parent Actor's testing** (New York and Tel Aviv, both otherwise dense Waze markets) despite working reliably in Indonesia and the UK. Cause not yet isolated — logged as a regional caveat rather than assumed fixed everywhere.
- **`nearby` doesn't support filtering by category.** The protocol has a `category` filter field, and real category strings were pulled straight from the app (`GAS_STATION`, `PARKING_LOT`, `CHARGING_STATION`, `EV_CHARGING_STATION`, ...), but every one tried returned zero results in testing, while leaving the filter unset reliably returns real nearby venues with their category already attached. Filter client-side on the `categories` field in the response for now.
- This is an unofficial, reverse-engineered integration, not affiliated with or endorsed by Waze / Google. Behavior may change if Waze changes its protocol.

### Pricing

Pay per event: **$0.006** per `place` — charged once for each search/nearby/reverse-geocode result row pushed to the dataset (Free plan price; lower on paid Apify plans). See the Actor's Pricing tab for current tiered rates.

Found a bug or have a feature request? Use the Issues tab on this Actor's page.

# Actor input Schema

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

Array of point queries to run. Each item needs "operation" (search | nearby | reverse-geocode), "lat", "lon", and operation-specific fields — see README.

## Actor input object example

```json
{
  "queries": [
    {
      "operation": "search",
      "query": "SPBU",
      "lat": -6.1754,
      "lon": 106.827,
      "maxResults": 3
    },
    {
      "operation": "nearby",
      "lat": -6.175,
      "lon": 106.827,
      "maxResults": 3
    },
    {
      "operation": "reverse-geocode",
      "lat": -6.1954,
      "lon": 106.8206
    }
  ]
}
```

# Actor output Schema

## `dataset` (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 = {
    "queries": [
        {
            "operation": "search",
            "query": "SPBU",
            "lat": -6.1754,
            "lon": 106.827,
            "maxResults": 3
        },
        {
            "operation": "nearby",
            "lat": -6.175,
            "lon": 106.827,
            "maxResults": 3
        },
        {
            "operation": "reverse-geocode",
            "lat": -6.1954,
            "lon": 106.8206
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("romy/waze-places-search-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 = { "queries": [
        {
            "operation": "search",
            "query": "SPBU",
            "lat": -6.1754,
            "lon": 106.827,
            "maxResults": 3,
        },
        {
            "operation": "nearby",
            "lat": -6.175,
            "lon": 106.827,
            "maxResults": 3,
        },
        {
            "operation": "reverse-geocode",
            "lat": -6.1954,
            "lon": 106.8206,
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("romy/waze-places-search-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 '{
  "queries": [
    {
      "operation": "search",
      "query": "SPBU",
      "lat": -6.1754,
      "lon": 106.827,
      "maxResults": 3
    },
    {
      "operation": "nearby",
      "lat": -6.175,
      "lon": 106.827,
      "maxResults": 3
    },
    {
      "operation": "reverse-geocode",
      "lat": -6.1954,
      "lon": 106.8206
    }
  ]
}' |
apify call romy/waze-places-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,romy/waze-places-search-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/y8f9Cfh03BvmANEAx/builds/Fxv356xcX3HIhiW8e/openapi.json
