# Google Flights Scraper: Fares, Airlines & Times (`subimpact/google-flights-scraper`) Actor

Search Google Flights and get one row per flight option: fare, airlines, flight numbers, times, airports, stops, layovers, aircraft, legroom and CO2. One-way or round trip, economy/business/first, 1-9 adults, any currency. $2.00 per 1,000 searches.

- **URL**: https://apify.com/subimpact/google-flights-scraper.md
- **Developed by:** [subimpact](https://apify.com/subimpact) (community)
- **Categories:** Travel, E-commerce, Automation
- **Stats:** 3 total users, 2 monthly users, 60.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 flight searches

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Flights Scraper: Fares, Airlines & Times

Search Google Flights and get every flight option on the results page as a clean row: fare, airline, flight numbers, departure and arrival times, airports, stops, layover airports with layover length, aircraft, legroom and CO2 emissions.

One-way or round trip, economy, business or first, 1 to 9 adults, any currency. Plain HTTPS requests, no browser, no Google API key, no cookies.

### What you get

One row per flight option, exactly as Google shows it:

- fare in the currency you ask for, plus a formatted price such as `$44`
- marketing airline names and one flight number per leg (`TR451`, or `VJ936` + `VJ820` for a connection)
- local departure and arrival time (`2026-12-01T11:15`), and how many days later it lands
- departure and arrival airport code and name
- total journey time in minutes, including layovers
- stops, and for each connection the airport, the layover length and whether it is an overnight stop
- aircraft type and legroom where Google publishes them
- Google's per-passenger CO2 estimate in kg and the percentage difference from typical emissions for the route
- which section the option came from: Google's Top flights (its best-fare picks) or the rest of the list
- the exact `google.com/travel/flights` URL the row was parsed from, so any row can be re-checked by hand

### Pricing

**$2.00 per 1,000 searches.** Every flight option on the results page is included in that one search charge.

- A search that returns at least one flight costs $0.002, whether the page lists 2 options or 60.
- A search that returns no flights costs nothing, and failed searches cost nothing.
- `maxSearches` (default 25) caps what a single run can spend: 25 searches is at most $0.05.
- You also pay the usual Apify platform usage for the run. At the default settings a run uses about 0.5 GB of memory for well under a minute.

### Input

The simplest run is one search. This is exactly the input the form shows:

```json
{
  "searches": [
    {
      "from": "KUL",
      "to": "SIN",
      "date": "2026-12-01",
      "returnDate": null,
      "adults": 1,
      "cabin": "economy"
    }
  ]
}
```

`from` and `to` take a 3-letter airport or city code (`KUL`, `SIN`) or a free-text city name (`Kuala Lumpur`, `Singapore`). `date` and `returnDate` are `YYYY-MM-DD`; leave `returnDate` empty or `null` for a one-way search. Dates must be today or later and at most 330 days ahead, which is as far out as Google sells fares.

Several searches in one run:

```json
{
  "searches": [
    { "from": "KUL", "to": "SIN", "date": "2026-12-01", "adults": 1, "cabin": "economy" },
    { "from": "SIN", "to": "HND", "date": "2026-12-01", "returnDate": "2026-12-08", "adults": 2, "cabin": "business" }
  ],
  "currency": "USD",
  "nonstopOnly": false,
  "maxFlightsPerSearch": 50
}
```

Instead of `searches` you can fill the shortcut fields `from`, `to`, `departureDate`, `returnDate`, `adults` and `cabin`. They are only used when `searches` is empty. With no input at all the actor runs the default search: Kuala Lumpur to Singapore, about 30 days from today, one way, economy, one adult.

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `searches` | array of objects | none (see prefill) | One object per search: `from`, `to`, `date`, `returnDate`, `adults`, `cabin` |
| `from` / `to` | string | none (see prefill) | Shortcut. Airport or city code, or a city name |
| `departureDate` | string | none | Shortcut. `YYYY-MM-DD` |
| `returnDate` | string | empty | Shortcut. Empty means one way |
| `adults` | integer | 1 | 1 to 9. The fare Google shows is the total for all adults |
| `cabin` | select | economy | `economy`, `business`, `first` |
| `currency` | string | USD | 3-letter code: USD, EUR, MYR, SGD, JPY |
| `language` | string | en | Google interface language (`hl`) |
| `country` | string | us | Google market (`gl`) |
| `nonstopOnly` | boolean | false | Only nonstop flights |
| `maxFlightsPerSearch` | integer | 50 | 1 to 300 options taken from each results page, cheapest first |
| `maxSearches` | integer | 25 | 1 to 200. Cost ceiling for the run |
| `maxConcurrency` | integer | 3 | 1 to 10 searches in parallel |
| `proxyConfiguration` | object | `{"useApifyProxy": false}` | Off by default: Google Flights answers direct requests from Apify containers |

### Output

One dataset row per flight option. Real rows from a run on 2026-10-25 (KUL to SIN, 2026-12-01, one way, economy, 1 adult), trimmed to the interesting fields:

```json
{
  "searchFrom": "KUL",
  "searchTo": "SIN",
  "searchDate": "2026-12-01",
  "searchReturnDate": null,
  "tripType": "one-way",
  "cabin": "economy",
  "adults": 1,
  "currency": "USD",
  "price": 44,
  "priceText": "$44",
  "isBestFlight": true,
  "airlines": ["Scoot"],
  "flightNumbers": ["TR451"],
  "departureAirport": { "code": "KUL", "name": "Kuala Lumpur International Airport" },
  "arrivalAirport": { "code": "SIN", "name": "Singapore Changi Airport" },
  "departureTime": "2026-12-01T11:15",
  "arrivalTime": "2026-12-01T12:35",
  "arrivalDayOffset": 0,
  "durationMinutes": 80,
  "stops": 0,
  "layovers": [],
  "aircraft": ["Boeing 787"],
  "legroom": "31 inches",
  "co2EmissionsKg": 49,
  "emissionsVsTypicalPct": -4,
  "parseStrategy": "structured"
}
```

A connecting option from the same crawl shape (KUL to HND, 2026-12-01, one way):

```json
{
  "price": 180,
  "airlines": ["Vietjet"],
  "flightNumbers": ["VJ936", "VJ820"],
  "departureTime": "2026-12-01T11:30",
  "arrivalTime": "2026-12-02T01:00",
  "arrivalDayOffset": 1,
  "durationMinutes": 750,
  "stops": 1,
  "layovers": [
    {
      "airportCode": "SGN",
      "airportName": "Tan Son Nhat International Airport",
      "durationMinutes": 295,
      "overnight": false
    }
  ],
  "aircraft": ["Airbus A321"],
  "legroom": "28 inches",
  "co2EmissionsKg": 430,
  "emissionsVsTypicalPct": 4
}
```

`layovers[].overnight` is true when the next leg leaves on a later calendar day or the stop lasts 8 hours or more. `price` is `null` when Google shows only a partner link for that option and no fare; the row is still delivered, and the search is still charged once because other rows did have fares.

The run summary is written to the key-value store as `RUN_SUMMARY`: one entry per search with the URL, options found, rows delivered, whether it was charged, and the reason for any search that returned nothing. A search that returns no flights also saves its page as `debug-<n>.html` (capped at 1 MB) so the empty result can be checked.

### How this compares

Apify Store flight scrapers, Free-plan list prices checked 25 October 2026:

| Actor | Free-plan price | Users (30 days) |
| --- | --- | --- |
| johnvc/Google-Flights-Data-Scraper-Flight-and-Price-Search | $0.03 per page processed + $0.02 per booking option (about $30 per 1,000 pages) | 394 |
| lergassy/google-flights-scraper | $0.20 per 1,000 flights | 306 |
| kaix/google-flights-scraper | $0.06 per 1,000 dataset items | 274 |
| memo23/google-flights-scraper | $0.005 start + $2.00 per 1,000 items | 168 |
| this actor | $2.00 per 1,000 searches, all options included | new |

Being straight about the arithmetic: per-flight pricing scales with how many options a page has. On the KUL to SIN page above (36 options) our flat $0.002 per search is about $0.06 per 1,000 flights, which is cheaper than the per-flight listings for that shape of search. On a thin page (two options) the same search still costs $0.002, and a per-flight rival is cheaper. What you get for the flat price is every option Google rendered, with the structured parts that raw HTML scraping tends to lose: layover airports and layover minutes, aircraft, legroom, the CO2 estimate and its difference from typical.

Competitor platform usage is not included in those prices; see each listing.

### Limits

- **Premium economy is not supported.** Google's search box accepts "business class" and "first class" and returns the matching cabin, but any query containing "premium economy" makes it fall back to an empty search form. Rather than silently return economy fares, the actor refuses `cabin: "premium-economy"` with an explanation.
- Only Google's first results page is parsed. That page carries roughly 20 to 60 options; `maxFlightsPerSearch` caps how many rows you get from it.
- Round trips return outbound options priced as the round-trip total, which is what Google shows. Return-leg selection needs a follow-up request per outbound option with Google's own selection token, and this actor does not do that.
- `adults` is the only passenger control. Google's search box also takes children and infants, but the price rules for them vary by fare and were not verified, so they are not offered.
- Prices are the numbers Google renders, in the currency you asked for. Google does the conversion; nothing here is an interbank rate.
- Google changes this page from time to time. If the layout moves, the actor does not guess: the row is not charged, the search is reported as an error in `RUN_SUMMARY`, and its HTML is saved for inspection.
- Requests go direct by default, which is what was measured to work from Apify containers. If you enable Apify Proxy and the proxy cannot be created, the search fails loudly instead of falling back to a direct request.

### Responsible use

This actor reads Google Flights' public search results, the same pages a browser gets, and follows `robots.txt` for `/travel/flights` (Google disallows `/search`, `/s/` and `/booking`, which this actor never touches). Keep runs reasonable: use `maxSearches` and `maxConcurrency` to avoid hammering Google, do not resell raw page dumps, and do not use the data to break a carrier's terms of sale. Fares change constantly, so treat any row as a snapshot with the `scrapedAt` timestamp and confirm on the airline's own site before buying.

# Actor input Schema

## `searches` (type: `array`):

One object per search. from/to accept a 3-letter airport or city code (KUL, SIN) or a free-text city name (Kuala Lumpur). date and returnDate are YYYY-MM-DD; returnDate null or empty means one way. adults 1-9, cabin economy, business or first. When this list is empty the shortcut fields below are used instead. Leave "date" out to search about 30 days from today.

## `from` (type: `string`):

Used only when Searches is empty. Departure airport or city: a 3-letter code such as KUL or a city name such as Kuala Lumpur.

## `to` (type: `string`):

Used only when Searches is empty. Arrival airport or city: a 3-letter code such as SIN or a city name such as Singapore.

## `departureDate` (type: `string`):

Used only when Searches is empty. YYYY-MM-DD, today or later, up to 330 days ahead. Empty means about 30 days from today.

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

Used only when Searches is empty. YYYY-MM-DD, on or after the departure date. Leave empty for a one-way search.

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

Number of adult passengers (1-9). Fares are the total for all adults, exactly as Google Flights shows them.

## `cabin` (type: `string`):

Cabin class. Every option was verified against live Google Flights pages in October 2026.

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

3-letter currency code for the prices, e.g. USD, EUR, MYR, SGD, JPY. Google converts the fare, so the numbers are Google's conversion, not an interbank rate.

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

2-letter Google interface language, e.g. en, ms, de. Prices, airline names and dates follow this language.

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

2-letter Google country code, e.g. us, my, sg, gb. It sets the Google Flights market (which points of sale and fare rules are shown); the currency comes from the Currency field.

## `nonstopOnly` (type: `boolean`):

Only show nonstop flights. Verified: Google returns just the nonstop options and the search shows the nonstop filter as applied.

## `maxFlightsPerSearch` (type: `integer`):

Upper limit of flight rows taken from each search's results page (1-300). A page usually lists 20-60 options that Google has already rendered; extra options are dropped, cheapest-first, and the drop is reported.

## `maxSearches` (type: `integer`):

Cost ceiling: at most this many searches are run (1-200). Every successful search costs $0.002, so the default 25 caps a run at $0.05. Searches above the cap are skipped and listed in RUN_SUMMARY.

## `maxConcurrency` (type: `integer`):

How many searches run at the same time (1-10). Higher is faster and more likely to get a soft rate limit from Google.

## `proxyConfiguration` (type: `object`):

Google Flights answers direct requests from Apify's datacenter IPs, so no proxy is used by default and the run costs nothing extra. Enable Apify Proxy (or your own proxy URLs) if you run very large jobs or see empty pages; a failed proxy setup then fails the search instead of quietly going direct.

## Actor input object example

```json
{
  "searches": [
    {
      "from": "KUL",
      "to": "SIN",
      "date": "2026-11-24",
      "returnDate": null,
      "adults": 1,
      "cabin": "economy"
    },
    {
      "from": "SIN",
      "to": "HND",
      "date": "2026-12-01",
      "returnDate": "2026-12-08",
      "adults": 2,
      "cabin": "business"
    }
  ],
  "from": "KUL",
  "to": "SIN",
  "adults": 1,
  "cabin": "economy",
  "currency": "USD",
  "language": "en",
  "country": "us",
  "nonstopOnly": false,
  "maxFlightsPerSearch": 50,
  "maxSearches": 25,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `flights` (type: `string`):

Every flight option parsed from the searches, one row per option

## `runSummary` (type: `string`):

Per-search outcome: URL, options found, rows delivered, charge, and the reason for any search that returned nothing

# 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 = {
    "searches": [
        {
            "from": "KUL",
            "to": "SIN",
            "adults": 1,
            "cabin": "economy"
        }
    ],
    "from": "KUL",
    "to": "SIN",
    "currency": "USD",
    "language": "en",
    "country": "us",
    "maxFlightsPerSearch": 50,
    "maxSearches": 25,
    "maxConcurrency": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("subimpact/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 = {
    "searches": [{
            "from": "KUL",
            "to": "SIN",
            "adults": 1,
            "cabin": "economy",
        }],
    "from": "KUL",
    "to": "SIN",
    "currency": "USD",
    "language": "en",
    "country": "us",
    "maxFlightsPerSearch": 50,
    "maxSearches": 25,
    "maxConcurrency": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("subimpact/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 '{
  "searches": [
    {
      "from": "KUL",
      "to": "SIN",
      "adults": 1,
      "cabin": "economy"
    }
  ],
  "from": "KUL",
  "to": "SIN",
  "currency": "USD",
  "language": "en",
  "country": "us",
  "maxFlightsPerSearch": 50,
  "maxSearches": 25,
  "maxConcurrency": 3
}' |
apify call subimpact/google-flights-scraper --silent --output-dataset

```

## MCP server setup

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