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

Search public flight fares by route and date. Export priced itineraries, airlines, schedules, stops, segments, and emissions to CSV or JSON.

- **URL**: https://apify.com/mlg14/google-flights-scraper.md
- **Developed by:** [MLG Data](https://apify.com/mlg14) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 83.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.30 / 1,000 results

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

Search Google Flights by airport pair and travel date, then export flight prices and schedules as structured CSV or JSON. Each saved row represents one priced itinerary, making this a practical Google Flights data source for fare comparisons, route monitoring, and travel analysis.

The scraper collects the initial public search results for a one-way or round-trip query. It records the displayed fare, operating airlines, departure and arrival times, journey duration, connections, segment details, and estimated emissions. Set a return date for a round-trip search, or leave it empty for a one-way search. Results are observations at the time of the run; fares and availability can change after collection.

### What data can you extract from Google Flights?

The default dataset has one row per priced itinerary. You can sort, filter, and export the rows directly. An itinerary may contain several flight segments; `legs` retains the segment details while the top-level fields make route comparisons simple.

| Field | Description | Example |
| --- | --- | --- |
| `flightId` | Identifier derived from route, date, flight numbers, and times | `f78661ac50c1e099ab60` |
| `tripType` | Requested trip type | `oneWay` |
| `resultCategory` | Position group shown in the search results | `best` |
| `departureAirport` | Origin airport code | `LAX` |
| `departureAirportName` | Full origin airport name | Airport name |
| `arrivalAirport` | Destination airport code | `JFK` |
| `arrivalAirportName` | Full destination airport name | Airport name |
| `outboundDate` | Requested outbound date | `2026-10-26` |
| `returnDate` | Requested return date or `null` | `null` |
| `departureTime` | Local departure date and time | `2026-10-26T16:30` |
| `arrivalTime` | Local arrival date and time | `2026-10-27T00:52` |
| `durationMinutes` | Outbound journey duration, including connections | `322` |
| `stops` | Number of connections | `0` |
| `stopAirports` | Connection airport codes in travel order | `[]` |
| `layoverMinutes` | Connection durations when the page exposes them | `[]` |
| `airline` | Primary operating airline name | Airline name |
| `airlineCode` | Primary airline code | `B6` |
| `airlines` | Distinct operating airline names | Array of names |
| `airlineCodes` | Distinct operating airline codes | `["B6"]` |
| `flightNumbers` | Flight numbers in travel order | `["B61024"]` |
| `price` | Displayed itinerary fare for the requested adults | `249` |
| `currency` | Currency of `price` | `USD` |
| `passengers` | Number of adults used in the search | `1` |
| `emissionsKg` | Estimated carbon dioxide equivalent in kilograms | `421` |
| `emissionsComparisonPercent` | Difference from typical flight emissions | `25` |
| `legs` | Segment records with carrier, airports, local times, duration, and aircraft | Array of objects |
| `bookingToken` | Opaque search token, not a booking URL | String or `null` |
| `searchUrl` | Public search page for the query | Search page URL |
| `searchedAt` | Collection timestamp in UTC | ISO timestamp |

Times are local to their respective airports and intentionally omit a timezone offset. An arrival on the next calendar day is represented by the next date in `arrivalTime`. `durationMinutes` is the elapsed itinerary duration provided by the search result, so it is the appropriate value for comparing flights across time zones. The emissions fields are estimates from the search page, not measured emissions. When a source value is unavailable, its field is `null` or an empty array as appropriate.

### How to scrape Google Flights

1. Enter a single departure airport code and a single arrival airport code. Use standard three-letter airport codes, such as `LAX` and `JFK`.
2. Choose an outbound date in `YYYY-MM-DD` format. Add `return_date` when you want a round-trip fare search. Leave it empty for one-way fares.
3. Set currency, country, and language if the defaults do not fit your market. Add optional limits for price, stops, airline codes, or number of saved rows.
4. Run the scraper. Open the output dataset to inspect each priced itinerary as a separate row.
5. Download the dataset in CSV or JSON for analysis, repeated monitoring, or a downstream workflow.

The route and date are checked against the page's own search state before any rows are saved. If the site interprets the query as a different route or trip type, the run fails clearly instead of returning mislabeled fares. Price, stop, and airline filters are applied to the itineraries exposed by the initial search page.

### Input

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `departure_id` | string | Required | One three-letter departure airport code. |
| `arrival_id` | string | Required | One three-letter arrival airport code. |
| `outbound_date` | string | Optional | Outbound date in `YYYY-MM-DD` format. Defaults to 30 days from today; past dates are shifted forward. |
| `return_date` | string | Empty | Add a later date for a round-trip search. |
| `adults` | integer | `1` | Number of adult travelers, from 1 to 9. |
| `currency` | string | `USD` | Three-letter currency code for displayed fares. |
| `hl` | string | `en` | Search page language code. |
| `gl` | string | `us` | Search page country code. |
| `max_price` | integer | Empty | Save only returned fares at or below this amount. |
| `max_stops` | integer | Empty | Save only itineraries with at most this many connections; `0` means nonstop. |
| `airlines` | string | Empty | Comma-separated operating airline codes, such as `AA,DL`. |
| `maxItems` | integer | `100` | Maximum rows to save. `0` keeps all itineraries exposed by the initial page. |
| `proxyConfiguration` | object | Enabled | Connection settings for requests. |

A one-way input used for a successful run:

```json
{
  "departure_id": "LAX",
  "arrival_id": "JFK",
  "outbound_date": "2026-10-26",
  "adults": 1,
  "currency": "USD",
  "hl": "en",
  "gl": "us",
  "maxItems": 100
}
```

For a round trip, add a later `return_date`, for example `2026-11-02`. The displayed price on a round-trip result is the fare shown for the outbound choice in that round-trip search. The first result page does not contain a confirmed return segment for each outbound choice. A return itinerary is selected in a later interaction on the site, so treat these rows as priced outbound options for the requested round trip rather than complete two-way tickets.

Use `max_stops: 0` for a nonstop comparison. Set `max_price` only after choosing the desired currency, since the amount is evaluated in the displayed currency. `airlines` accepts codes separated by commas; an itinerary is kept if at least one operating airline matches. This is useful when comparing service involving a preferred carrier, including itineraries with more than one carrier. A filter can reduce the output to zero rows if no initial result matches.

### Output example

The successful one-way LAX to JFK run on 2026-09-27 saved 34 priced itineraries. The following is a shortened selection of fields from its first row. The omitted fields follow the table above.

```json
{
  "flightId": "f78661ac50c1e099ab60",
  "tripType": "oneWay",
  "resultCategory": "best",
  "departureAirport": "LAX",
  "arrivalAirport": "JFK",
  "outboundDate": "2026-10-26",
  "returnDate": null,
  "departureTime": "2026-10-26T16:30",
  "arrivalTime": "2026-10-27T00:52",
  "durationMinutes": 322,
  "stops": 0,
  "stopAirports": [],
  "airlineCode": "B6",
  "airlineCodes": ["B6"],
  "flightNumbers": ["B61024"],
  "price": 249,
  "currency": "USD",
  "passengers": 1,
  "emissionsKg": 421,
  "emissionsComparisonPercent": 25
}
```

A row with a connection has `stops` greater than zero and includes each flight in `legs`. This lets you compare the overall fare and elapsed time without losing the details of the individual segments. Exported CSV is convenient for flat comparisons; JSON preserves the full segment array. The fare is a snapshot, so a later run may show a different amount for the same `flightId`.

### Use cases

- **Fare monitoring:** Save repeated searches for the same route and date, then compare `price` alongside `searchedAt`. This can reveal when a displayed fare changes. Keep the timestamp because a search result has no guaranteed validity period.
- **Departure time comparison:** Filter a dataset by `departureTime` and `arrivalTime` to identify schedules that fit a meeting, connection, or arrival window. Use `durationMinutes` for elapsed travel time.
- **Nonstop route checks:** Set `max_stops` to `0` to collect only nonstop options already present in the initial search result set. Compare airline codes and fares across dates.
- **Connection analysis:** Inspect `stopAirports`, `layoverMinutes`, and `legs` to understand whether a lower fare involves longer travel or a particular connecting airport.
- **Emissions comparison:** Place `emissionsKg` next to fare and duration when evaluating alternatives. The figure is an estimate supplied with the search result.
- **Market sampling:** Run the same query with different country and currency settings to collect fare displays for the markets you serve. Keep those settings with your own saved search definitions when comparing results.

### How much does it cost to scrape Google Flights?

The configured result event is **$0.30 per 1,000 saved flight rows**, or **$0.0003 per row**. The successful 34-row example therefore represents **$0.0102** in result events. A 100-row set represents **$0.03**; 5,000 rows collected across many searches represent **$1.50**. A single query typically exposes far fewer than 5,000 rows, so larger datasets require multiple routes or dates.

Charges follow saved rows, not search attempts or result pages. `maxItems` caps how many rows are saved in a run. A strict price, stop, or airline filter can reduce the charged row count because unmatched itineraries are not saved. Check the current event price shown in the run interface before planning a large schedule; listed rates may change over time. The run also uses the platform resources needed to execute the search.

### Tips for best results

Start with one airport pair and a date that has published schedules. The search source accepts one origin code and one destination code per run; use separate runs when comparing several airports. Dates farther in the future can return fewer options if schedules or fares have not been released. Past dates are not useful for live fare collection.

Run the query without filters first if you need to understand the range of fares and connection counts. Then add `max_price`, `max_stops`, or `airlines` to narrow the saved dataset. These filters act on the initial rows returned by the site; they do not trigger an exhaustive search for more matching flights. In particular, filtering for a rare airline may leave only a few rows even when the site has more options behind later interactions.

Keep currency consistent when tracking a route over time. A numeric fare in one currency is not directly comparable with the same number in another. Record the number of adults as well: a fare displayed for two adults should not be mixed with fares for one adult. The dataset repeats `currency` and `passengers` on every row to make accidental mixing easier to detect.

For time comparisons, read `departureTime` in the origin airport's local time and `arrivalTime` in the destination airport's local time. The timestamps do not include offsets. Use `durationMinutes` for elapsed time, and inspect the calendar date portion when a flight arrives after midnight. Flight numbers and times help identify a schedule, while `flightId` supports joins across repeated runs; it is not a reservation identifier.

### Limits

Only the first public result set is collected. The site may reveal more itineraries after an interactive continuation, and there is no confirmed public continuation token in this source. On the tested one-way route, the first set held 34 priced itineraries. Other routes may return more, fewer, or none. The `maxItems` setting can only reduce that number.

One-way and round-trip route searches are supported. The public text query did not reliably produce a priced multi-city itinerary, so multi-city combinations are not offered. A single input also does not accept several origins or destinations. Children and infant passenger counts are not supported. The scraper rejects these unsupported values if passed programmatically, avoiding a result that silently uses a different passenger group.

A round-trip query yields priced outbound choices for the requested travel dates. It does not confirm a specific return flight or booking seller. `bookingToken` is an internal search value and cannot be used as a direct checkout link. No booking options, baggage fee breakdown, fare family, historical price band, or price prediction is claimed. The displayed fare may change when the itinerary is selected or when optional services are added.

The search page can change its structured data layout without notice. Route and date validation guards against one common failure mode, but a layout change can still interrupt extraction. Empty optional values are retained as `null` or empty arrays rather than filled with guesses. Public site access may vary by location or request volume.

### Use with automated workflows

A saved search can run on a schedule and append fresh rows to a time series. For example, configure a daily LAX to JFK search for one departure date, then compare the minimum `price` in each run. Another workflow can run nonstop searches on several dates and export each dataset to a spreadsheet. Use `searchedAt`, route, date, currency, and passenger count as the grouping keys before comparing fares.

When a downstream process needs one flight at a time, read the default dataset directly. Each row is already an itinerary rather than a page containing arrays of flights. When a process needs connection detail, keep the JSON `legs` array or expand it into a separate segment table using `flightId` as the link. Check the run status before using a dataset: a failed search should not be interpreted as zero available flights.

### FAQ

#### Is this limited to public flight results?

Yes. The scraper reads a public search page and saves displayed itinerary information. You are responsible for using collected data in accordance with applicable terms and laws. Do not use the output to imply that a fare is guaranteed or that a ticket has been held.

#### Do I need to configure a proxy?

The default connection setting is already enabled. You can supply your own compatible proxy configuration when needed. Requests can still be limited by the site, especially at high frequency. Space repeated runs sensibly and monitor failures rather than assuming every route always returns the same number of rows.

#### How quickly does a run finish?

The measured golden run completed after fetching and parsing one search page and saved 34 rows. Actual duration depends on build startup, page response time, connection routing, and platform load. The workflow makes one main search request per run, with retries only when the shared fetch layer encounters a block or error.

#### Can I schedule price checks?

Yes. Save a route and date as a task, schedule it, and compare datasets from successive runs. Keep the date current if your workflow should always look ahead by a fixed number of days. The input date itself is a fixed calendar date, not a rolling offset.

#### Can I export to a spreadsheet?

Yes. Download the dataset as CSV for a flat fare table, or use JSON when you need the full `legs` array. Price, airline, duration, stop count, and local times are separate fields, so you can sort or chart them without parsing a long text description.

#### Why is a field empty?

Some details are not supplied for every itinerary. For example, a nonstop flight has no stop airport or layover minutes, and an emissions estimate can be absent. Empty values indicate that the page did not expose a usable value for that row.

#### Why do I see fewer flights after adding a filter?

Filters are applied to the initial priced result set. A maximum price, nonstop limit, or airline list can remove rows. The scraper does not load every possible flight that an interactive search might reveal, so the filtered dataset is a subset of the first set, not an exhaustive market inventory.

### Integrations

Use the dataset endpoint to read results from your own application, or export CSV and JSON for a reporting pipeline. Scheduled runs, webhooks, and saved tasks can connect new fare observations to alerts or recurring analysis. Include route, dates, currency, passenger count, and collection time in any downstream record so comparisons remain meaningful.

### Support

Open an issue on the Issues tab; we reply within 24h and add fields on request.

# Actor input Schema

## `departure_id` (type: `string`):

One three-letter IATA airport code, such as LAX. The search is for one departure airport.

## `arrival_id` (type: `string`):

One three-letter IATA airport code, such as JFK. The search is for one arrival airport.

## `outbound_date` (type: `string`):

Departure date in YYYY-MM-DD format. Leave empty for 30 days from today. Dates in the past are shifted to 30 days from today.

## `return_date` (type: `string`):

Optional return date in YYYY-MM-DD format. Leave empty for a one-way search.

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

Number of adult travelers included in the displayed price.

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

Three-letter currency code for displayed prices, such as USD or EUR.

## `hl` (type: `string`):

Language code for the search page, such as en.

## `gl` (type: `string`):

Country code for the search page, such as us.

## `max_price` (type: `integer`):

Keep only returned itineraries at or below this displayed price.

## `max_stops` (type: `integer`):

Keep itineraries with at most this many stops. Set 0 for nonstop flights.

## `airlines` (type: `string`):

Optional comma-separated airline codes, such as AA,DL. Keep matching returned itineraries.

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

Maximum flight rows to save. Set 0 for every itinerary exposed in the initial result set.

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

Proxy configuration for flight search requests. The default uses the configured proxy.

## Actor input object example

```json
{
  "departure_id": "LAX",
  "arrival_id": "JFK",
  "adults": 1,
  "currency": "USD",
  "hl": "en",
  "gl": "us",
  "airlines": "",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per priced itinerary in the default dataset.

# 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 = {
    "departure_id": "LAX",
    "arrival_id": "JFK"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mlg14/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 = {
    "departure_id": "LAX",
    "arrival_id": "JFK",
}

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

```

## MCP server setup

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