# Google Flights Scraper (`meticulous_ground/google-flights-scraper`) Actor

Scrape Google Flights itineraries as flat rows: live price, airlines, departure/arrival times, duration, stops, layovers, aircraft, CO2 estimate, and a shareable deep link. One-way or round-trip, any cabin class or currency. Pay only for delivered rows - failed fetches cost nothing.

- **URL**: https://apify.com/meticulous\_ground/google-flights-scraper.md
- **Developed by:** [Aaron S](https://apify.com/meticulous_ground) (community)
- **Categories:**
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 Flights Scraper

Get live Google Flights prices as flat, ready-to-use rows - one row per itinerary, with airlines, times, duration, stops, layovers, aircraft, and CO2 estimates. One-way or round-trip, any cabin class, any currency. No charge for failed fetches.

### Try it

Paste this into the input editor and hit Run:

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departDate": "2026-09-25",
  "returnDate": "",
  "adults": 1,
  "cabinClass": "economy",
  "currency": "GBP",
  "maxItems": 50
}
```

#### Input fields

| Field | Type | Values | Notes |
|---|---|---|---|
| `origin` | string | 3-letter IATA code, e.g. `LHR`, `JFK`, `NYC` | Airport codes and metro/city codes both work |
| `destination` | string | 3-letter IATA code | Same as origin |
| `departDate` | string | `YYYY-MM-DD` | Must be today or later |
| `returnDate` | string | `YYYY-MM-DD` or empty | Empty = one-way. When set, rows are departing-flight options priced as round-trip totals (how Google Flights itself works) |
| `adults` | integer | 1-9 | Default 1 |
| `cabinClass` | string | `economy` | `premium_economy` | `business` | `first` | Default `economy` |
| `currency` | string | ISO code, e.g. `USD`, `GBP`, `EUR` | Prices returned in this currency |
| `maxItems` | integer | e.g. `50` | Caps rows delivered before the run stops |
| `proxyGroups` | array | e.g. `["RESIDENTIAL"]` | RESIDENTIAL (default) recommended - Google blocks datacenter IPs on the Flights surface |

One query returns the **complete** result set for that route and date (typically 10-30 itineraries) in a single request - there is no pagination to pay for.

### Output

Flat rows, one per itinerary. No nested objects to unpack - multi-leg details come as compact `|`-delimited strings. Real example row (LHR-JFK one-way, economy):

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departDate": "2026-09-25",
  "returnDate": "",
  "cabinClass": "economy",
  "adults": 1,
  "currency": "GBP",
  "fetchedAt": "2026-08-26T12:00:00.000Z",
  "category": "best",
  "price": 602,
  "priceCurrency": "GBP",
  "airlineCodes": "B6",
  "airlineNames": "JetBlue",
  "departureAirport": "LHR",
  "departureTime": "2026-09-25 08:15",
  "arrivalAirport": "JFK",
  "arrivalTime": "2026-09-25 11:19",
  "durationMinutes": 484,
  "stops": 0,
  "layovers": "",
  "flightNumbers": "B62220",
  "legs": "B62220 LHR 2026-09-25 08:15 -> JFK 2026-09-25 11:19",
  "aircraft": "Airbus A321neo",
  "co2Grams": 537000,
  "co2TypicalGrams": 484000,
  "deepLink": "https://www.google.com/travel/flights/search?tfs=GhoSCjIwMjYtMDktMjVqBRIDTEhScgUSA0pGS0IBAUgBmAEC&hl=en&curr=GBP"
}
```

A connecting itinerary fills the multi-leg fields:

```json
{
  "airlineNames": "Tap Air Portugal",
  "price": 519,
  "stops": 1,
  "layovers": "LIS 490m",
  "flightNumbers": "TP1363 | TP209",
  "legs": "TP1363 LHR 2026-09-25 06:00 -> LIS 2026-09-25 08:45 | TP209 LIS 2026-09-25 16:55 -> JFK 2026-09-25 20:05",
  "durationMinutes": 1145
}
```

- `category` is `best` (Google's ranked picks) or `other` (the rest of the result set).
- `deepLink` opens the exact same search in Google Flights - hand it to users for booking.
- `co2Grams` is Google's per-passenger CO2e estimate for the itinerary; `co2TypicalGrams` is the route-typical value it is compared against.

Queries that fail after retries are logged to a separate `google-flights-errors` dataset (`origin`, `destination`, `departDate`, `reason`, `fetchedAt`) instead of leaving a silent gap in your results.

### Coming from fast-flights?

The [fast-flights](https://github.com/AWeirdDev/flights) Python library proves this route works - but you run it, patch it when Google changes internals, and supply your own unblocked IPs. This actor is the same server-rendered `?tfs=` route as a managed service: residential proxy rotation, session-scoped cookies, retries with identity rotation, block detection, and flat rows with layovers and flight numbers already extracted.

| fast-flights | This actor |
|---|---|
| `FlightData(date=..., from_airport="LHR", to_airport="JFK")` | `"origin": "LHR", "destination": "JFK", "departDate": ...` |
| `Passengers(adults=2)` | `"adults": 2` |
| `seat="business"` | `"cabinClass": "business"` |
| `trip="round-trip"` + second `FlightData` | just set `"returnDate"` |
| bring your own proxy | residential rotation built in |
| `Result.flights[n].price` | flat rows with price, layovers, flight numbers, CO2 |

### How this compares

|  | This actor | Typical Flights actors on the Store |
|---|---|---|
| Charge on failed queries | Never - only delivered rows are billed | Often bill per run or per started query |
| Actor start | Free - no per-run fee | Some charge a flat fee before any data lands |
| Output shape | Flat rows, one per itinerary | Frequently nested per-search JSON you have to unpack |
| Reliability approach | Session rotation (Crawlee session pool), bounded retries with identity rotation, block detection | Not usually documented in the listing |

### Pricing

Pay-per-event, priced on delivered rows: you're billed only once itinerary rows land in your dataset. Starting a run costs nothing. If a query fails after retries, it goes to the errors dataset instead, and you pay nothing for it.

### Using the API

#### Apify API (HTTP)

```bash
curl "https://api.apify.com/v2/acts/meticulous_ground~google-flights-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "origin": "LHR",
    "destination": "JFK",
    "departDate": "2026-09-25",
    "currency": "GBP"
  }'
```

#### JavaScript (apify-client)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('meticulous_ground/google-flights-scraper').call({
  origin: 'LHR',
  destination: 'JFK',
  departDate: '2026-09-25',
  returnDate: '2026-10-02',
  cabinClass: 'economy',
  currency: 'GBP',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python (apify-client)

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor("meticulous_ground/google-flights-scraper").call(run_input={
    "origin": "EDI",
    "destination": "LHR",
    "departDate": "2026-09-25",
    "currency": "GBP",
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

Run one query per Actor call - each call returns that route and date's complete itinerary set.

# Actor input Schema

## `origin` (type: `string`):

3-letter IATA airport or city code to fly from, e.g. LHR, JFK, NYC, LON.

## `destination` (type: `string`):

3-letter IATA airport or city code to fly to, e.g. JFK, LHR, NYC.

## `departDate` (type: `string`):

Departure date as YYYY-MM-DD (must be today or later).

## `returnDate` (type: `string`):

Optional return date as YYYY-MM-DD. Leave empty for a one-way search. When set, rows are departing-flight options priced as round-trip totals (how Google Flights itself works).

## `adults` (type: `integer`):

Number of adult passengers (1-9).

## `cabinClass` (type: `string`):

Cabin class to search.

## `currency` (type: `string`):

3-letter currency code for prices, e.g. USD, GBP, EUR.

## `maxItems` (type: `integer`):

Maximum itinerary rows to deliver before stopping. Caps what you pay for. A flight query returns its complete result set (typically 10-30 itineraries) in one request.

## `proxyGroups` (type: `array`):

Apify proxy groups. RESIDENTIAL (default) is required in practice - Google blocks datacenter IPs on the Flights surface, and the GOOGLE\_SERP group does not reach google.com/travel.

## `debugCapture` (type: `boolean`):

Saves each raw fetched HTML page to the run's key-value store (RAW\_PAGE\_n) for diagnosing parser issues. Leave off in normal use.

## `debugFetchUrl` (type: `string`):

Maintenance only. Fetches this single https://www.google.com/travel/... URL through the configured proxy, stores the raw body to the key-value store (DEBUG\_FETCH), and exits without charging.

## Actor input object example

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "returnDate": "",
  "adults": 1,
  "cabinClass": "economy",
  "currency": "USD",
  "maxItems": 50,
  "proxyGroups": [
    "RESIDENTIAL"
  ],
  "debugCapture": false,
  "debugFetchUrl": ""
}
```

# Actor output Schema

## `results` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("meticulous_ground/google-flights-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("meticulous_ground/google-flights-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 '{}' |
apify call meticulous_ground/google-flights-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,meticulous_ground/google-flights-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/auFEi1pErIO6qOWOe/builds/PtOHv9laEIIrmTPpv/openapi.json
