# Google Maps Directions & Distance Matrix Scraper (`steadyscrape/google-maps-directions-scraper`) Actor

Scrape Google Maps directions and a distance matrix: driving, transit, walking and bicycling routes between addresses, places or coordinates, with distance, travel time in traffic, typical range, via roads, alternatives, steps, transit times and fares. Export to JSON, CSV or Excel, or via API.

- **URL**: https://apify.com/steadyscrape/google-maps-directions-scraper.md
- **Developed by:** [Steady Scrape](https://apify.com/steadyscrape) (community)
- **Categories:** Travel, Business, Developer tools
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 routes

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 Maps Directions & Distance Matrix Scraper (driving, transit, walking, bicycling)

Scrape **Google Maps directions** between any places: the **distance, the travel time, the time in traffic and the
range Google expects** at that hour, the **roads the route goes via**, the **alternatives** Google offers, and for
**public transit the departure and arrival times, the lines, the agencies and the fare**. Ask one trip, a
**multi-stop trip** (up to 10 stops), or a whole **distance matrix** (every origin × every destination), by car, transit,
on foot or by bike, now or at a time you choose. Turn-by-turn steps on request.

Stops are typed as you would in Google Maps: an address, a business or landmark name, a city, or coordinates. No login,
no browser, no Google API key. Export the routes to JSON, CSV or Excel, or read them through the API.

### What you can do with Google Maps directions data

- **A distance matrix for logistics and field teams**: drive time and distance from every warehouse, store or
  technician to every customer, in one run, with traffic at the hour they leave.
- **Commute and real-estate analysis**: travel time from a list of homes to an office or a school, by car and by
  transit at 8 AM (`departAt`), with the typical range Google expects.
- **Delivery and service-area planning**: which ZIP codes or towns are within 30 minutes of a site.
- **Route research**: the roads each alternative takes, whether it has tolls, Google's note ("Fastest route now due to
  traffic conditions"), and the toll-free option (`avoidTolls`).
- **Transit research**: the lines, agencies, departure times and fares of the itineraries Google offers between two
  places, with each ride's stops when steps are on.
- **Travel-time monitoring**: schedule the Actor with `departInHours` and record how drive times change over days.

### Input

| field | what it does |
|---|---|
| `trips` | One trip per line, stops separated by `->`: `Austin, TX -> Dallas, TX`, or `Austin, TX -> Waco, TX -> Dallas, TX` for a multi-stop trip. `→` and `\|` work too. Up to 500. |
| `origins`, `destinations` | A distance matrix: every origin is paired with every destination (up to 50 × 50). An origin equal to a destination is a free `same_place` row. |
| `travelModes` | `driving` (default), `transit`, `walking`, `bicycling`. Each trip is asked once per mode, one row each. |
| `routesPerTrip` | Google's best route plus its alternatives, 1–6 (default 3). Alternatives cost nothing extra. |
| `includeSteps` | Turn-by-turn instructions for every route and leg, and each transit ride's line, stops and times. |
| `departInHours` | Leave N hours after the run starts (0 = now). Traffic and timetables at that hour. Good for schedules. |
| `departAt` | Leave at a local date and time at the first stop: `2026-11-20 08:00`. Replaces `departInHours`. |
| `avoidTolls`, `avoidHighways`, `avoidFerries` | Route options, as in Google Maps. |
| `language`, `country` | Language of Google's texts (`en`, `es`, `de`…) and the country it answers for (`us`, `gb`…). |

A stop that reads as coordinates (`30.2672,-97.7431`) is asked as a point on the map; anything else as typed text.

#### Input example: a distance matrix by car at 8 AM

```json
{
    "origins": ["Austin, TX", "Round Rock, TX"],
    "destinations": ["Georgetown, TX", "San Marcos, TX"],
    "travelModes": ["driving"],
    "routesPerTrip": 1,
    "departAt": "2026-11-20 08:00"
}
```

#### Input example: trips by transit and on foot, with steps

```json
{
    "trips": ["Times Square, New York -> Brooklyn Bridge Park"],
    "travelModes": ["transit", "walking"],
    "includeSteps": true
}
```

### Output: one row per trip and travel mode

Each row carries the best route's fields at the top, so a matrix exports straight to a spreadsheet, and every route
Google offered (best first) in `routes`, each with its legs (and steps when asked).

```json
{
    "rowType": "route",
    "source": "trip",
    "inputIndex": 1,
    "trip": "Austin, TX -> Dallas, TX",
    "origin": "Austin, TX",
    "destination": "Dallas, TX",
    "originIndex": null,
    "destinationIndex": null,
    "travelMode": "driving",
    "departure": null,
    "via": "I-35 N and I-35E N",
    "distanceMeters": 315398,
    "distanceKm": 315.4,
    "distanceMiles": 195.98,
    "distanceText": "196 miles",
    "durationSeconds": 10685,
    "durationText": "2 hr 58 min",
    "durationInTrafficSeconds": 10689,
    "durationInTrafficText": "2 hr 58 min",
    "typicalDurationMinSeconds": 10364,
    "typicalDurationMaxSeconds": 11994,
    "typicalDurationText": "2 hr 53 min to 3 hr 20 min",
    "summary": "Fastest route now, avoids road closure on Cadiz St",
    "notices": [],
    "hasTolls": false,
    "originResolved": "Austin, Texas",
    "destinationResolved": "Dallas, Texas",
    "originLat": 30.267153,
    "originLng": -97.7430608,
    "destinationLat": 32.7766642,
    "destinationLng": -96.7969879,
    "stops": [
        { "input": "Austin, TX", "name": "Austin", "label": "Austin, Texas", "lat": 30.267153, "lng": -97.7430608, "placeId": "ChIJLwPMoJm1RIYRetVp1EtGm10" },
        { "input": "Dallas, TX", "name": "Dallas", "label": "Dallas, Texas", "lat": 32.7766642, "lng": -96.7969879, "placeId": "ChIJS5dFe_cZTIYRj2dH9qSb7Lk" }
    ],
    "routes": [
        { "via": "I-35 N and I-35E N", "distanceMeters": 315398, "durationSeconds": 10685, "legs": [{ "toStop": "Dallas", "distanceMeters": 315398, "durationSeconds": 10685, "steps": null }] },
        { "via": "I-35 N", "distanceMeters": 325712, "durationSeconds": 11405, "legs": ["…"] },
        { "via": "I-35 N and I-45 N", "distanceMeters": 346782, "durationSeconds": 11995, "legs": ["…"] }
    ],
    "mapsUrl": "https://www.google.com/maps/dir/Austin,+TX/Dallas,+TX/data=!4m2!4m1!3e0",
    "scrapedAt": "2026-11-03T06:41:24.939Z"
}
```

A transit row also fills `departureTime` / `arrivalTime` (UTC), `departureTimeText` / `arrivalTimeText` ("8:20 AM",
local), `timeZone`, `fareAmount`, `fareCurrency`, `fareText`, `transitLines` (`["2"]`) and `transitAgencies` (`null` or
empty on other modes; the example above leaves them out). With steps, a ride reads:

```json
{
    "travelMode": "transit",
    "durationSeconds": 1110,
    "durationText": "18 min",
    "transit": { "line": "2", "vehicle": "subway", "headsign": "New Lots Av", "agency": "MTA New York City Transit", "departureStop": "Times Sq-42 St", "arrivalStop": "Clark St", "departureTime": "2026-11-04T13:23:00.000Z", "stopCount": 7 }
}
```

#### Row fields

| field | meaning |
|---|---|
| `rowType` | `route` for a trip Google planned (charged), `trip` for a free row that says why there is no route. |
| `source`, `inputIndex` | `trip` (a line of `trips`, its position) or `matrix` (an origin × destination pair, its number). |
| `trip`, `origin`, `destination` | The stops as you typed them, joined with `->`; the first and the last. |
| `originIndex`, `destinationIndex` | A matrix pair's positions in `origins` and `destinations`; `null` for a trip line. |
| `travelMode`, `departure` | The mode asked, and the departure asked (`null` for now). |
| `originResolved`, `destinationResolved`, `originLat`, `originLng`, `destinationLat`, `destinationLng` | Where Google placed the first and the last stop. |
| `stops` | Every stop as Google resolved it: name, full label, coordinates, place id. |
| `routes` | Every route Google offered, best first (the row's own route fields repeat the first), each with its `legs`. |
| `mapsUrl` | The same trip on Google Maps, to open in a browser. |
| `scrapedAt` | When the run read it (UTC). |

#### Route fields

The best route's fields sit at the top of the row; every route in `routes` carries the same ones.

| field | meaning |
|---|---|
| `distanceMeters`, `distanceKm`, `distanceMiles`, `distanceText` | The route's length, and Google's own text for it. |
| `durationSeconds`, `durationText` | Google's travel time for the route. |
| `durationInTrafficSeconds`, `durationInTrafficText` | Driving: the time with traffic at the departure asked (now by default). |
| `typicalDurationMinSeconds`, `typicalDurationMaxSeconds`, `typicalDurationText` | Driving: the range Google expects at that time of day ("21–27 min"). |
| `via` | The roads the route takes, as Google summarizes them. |
| `summary`, `notices`, `hasTolls` | Google's note on why it ranks the route, its notices ("This route has tolls.", "This route includes a ferry."). |
| `departureTime`, `arrivalTime`, `timeZone`, `fare…`, `transitLines`, `transitAgencies` | Transit only. |
| `legs` | One per stretch between consecutive stops: `toStop`, distance, duration, and `steps` when asked. |

#### Free rows

A trip that gives no route is a row with `rowType: "trip"`, a `status` and a `reason`, and is never charged:
`place_not_found` (Google cannot find a stop, named in `stopNotFound`), `no_route` (no route in that mode, e.g. driving
across an ocean or transit where there is none), `same_place`, `invalid` (one stop, more than ten), `blocked`, and
`spending_limit`.

### Pricing

- **US$0.002 per route**: one trip in one travel mode, with Google's alternatives included (US$2 per 1,000; a 30 × 30
  distance matrix is 900 routes, US$1.80).
- **US$0.003 per route with steps**, when `includeSteps` is on.

Free rows are never charged, and the run stops at your spending limit. Google's own Distance Matrix API bills US$0.005
an element.

### How it reads Google Maps, and when Google asks for verification

It asks Google Maps the same question its own directions page asks when you open a `/maps/dir/` link, over HTTP, at a
person's pace: one request per trip and mode, two in flight. **If Google asks an IP for verification** — its "unusual
traffic" page, a CAPTCHA, a JavaScript check, or any answer that is not Google Maps' normal data — **that IP is done for
the run**: nothing more is sent from it, and the run goes on from another IP of Apify's datacenter proxy. It never
solves, bypasses or replays a challenge. Plain overloads (HTTP 429 or 5xx without a challenge) take the same way. When
every IP the run can use has been refused, the trips left are free `blocked` rows that say so, and the run ends
normally with a message to try again later.

### Limits

- Up to 500 trips and a 50 × 50 matrix per run; up to 10 stops per trip; up to 6 routes per trip.
- A stop typed as text is resolved the way Google Maps resolves it; set `country` to the trips' country so a bare
  "Springfield" means the right one, or type the state or postcode.
- "Arrive by" is not offered: Google Maps answers driving trips with no clock times, so only departures are asked.
- Transit needs a departure from today on: Google has no timetables for a past date, so a past `departAt` gives
  transit trips a free `no_route` row (driving, walking and bicycling still answer).
- Route shapes (polylines) are not delivered.

### Is it legal?

It reads directions Google Maps shows to anyone, without logging in, at a pace a person planning trips could produce.
Routes are not personal data. Use the data in line with Google's terms and the laws that apply to you.

This Actor is not affiliated with, endorsed by or sponsored by Google. Google and Google Maps are trademarks of
Google LLC.

# Actor input Schema

## `trips` (type: `array`):

One trip per line, its stops separated by <code>-></code>: <code>Austin, TX -> Dallas, TX</code>. A stop is an address, a place's name, a city or coordinates (<code>30.2672,-97.7431</code>). Add stops in between for a multi-stop trip: <code>Austin, TX -> Waco, TX -> Dallas, TX</code> (up to 10 stops). Up to 500 trips.

## `origins` (type: `array`):

For a distance matrix: the places trips start from, one per line. Every origin is paired with every destination below (5 origins × 4 destinations = 20 routes). Up to 50.

## `destinations` (type: `array`):

For a distance matrix: the places trips end at, one per line. Up to 50.

## `travelModes` (type: `array`):

Each trip is asked once per mode chosen; each answer is one route.

## `routesPerTrip` (type: `integer`):

Google's best route first, then the alternatives it offers (up to 3 for driving, 6 for transit). Alternatives are included in the price of the trip.

## `includeSteps` (type: `boolean`):

Every instruction of every route ("Turn left onto Brazos St", 0.1 mi, 1 min), and for transit each ride's line, stops and times. Charged as a route with steps.

## `departInHours` (type: `integer`):

Plan the trips as leaving N hours after the run starts: traffic and transit timetables at that hour. 0 leaves now. Works with schedules: <code>12</code> always asks for half a day later.

## `departAt` (type: `string`):

A date and time at the first stop, as <code>YYYY-MM-DD HH:MM</code> (<code>2026-11-20 08:00</code> for 8 AM there). When set, it replaces "Depart in N hours". Transit needs a date from today on: Google has no timetables for past dates.

## `avoidTolls` (type: `boolean`):

Driving routes that avoid toll roads when Google finds one.

## `avoidHighways` (type: `boolean`):

Driving routes that avoid highways.

## `avoidFerries` (type: `boolean`):

Routes that avoid ferries.

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

Language of Google's texts ("2 hr 58 min", the steps, road names), as a code: <code>en</code>, <code>es</code>, <code>de</code>, <code>pt-BR</code>. Distances and durations are also given in metres and seconds.

## `country` (type: `string`):

Two-letter country code Google answers for (<code>us</code>, <code>gb</code>, <code>de</code>). It decides which "Springfield" a bare name means: use the trips' country.

## Actor input object example

```json
{
  "trips": [
    "Austin, TX -> Dallas, TX"
  ],
  "travelModes": [
    "driving"
  ],
  "routesPerTrip": 3,
  "includeSteps": false,
  "departInHours": 0,
  "departAt": "",
  "avoidTolls": false,
  "avoidHighways": false,
  "avoidFerries": false,
  "language": "en",
  "country": "us"
}
```

# Actor output Schema

## `routes` (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 = {
    "trips": [
        "Austin, TX -> Dallas, TX"
    ],
    "travelModes": [
        "driving"
    ],
    "routesPerTrip": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyscrape/google-maps-directions-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 = {
    "trips": ["Austin, TX -> Dallas, TX"],
    "travelModes": ["driving"],
    "routesPerTrip": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("steadyscrape/google-maps-directions-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 '{
  "trips": [
    "Austin, TX -> Dallas, TX"
  ],
  "travelModes": [
    "driving"
  ],
  "routesPerTrip": 3
}' |
apify call steadyscrape/google-maps-directions-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyscrape/google-maps-directions-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/flcUifsP3HbdBwwdr/builds/qNX4VXVP1aUwSH7dA/openapi.json
