# Google Flights Scraper | Fares, Price Calendar & Alerts (`alexmorain/google-flights-scraper`) Actor

Scrape Google Flights fares and flights: one-way, round trip, multi-city legs, flexible-date price calendar, Google's low/typical/high verdict and 60-day price history. Monitor mode returns only price drops, with webhook alerts. Plain HTTP.

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

## Pricing

from $1.50 / 1,000 fares

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 Google Flights Scraper do?

Google Flights Scraper reads [Google Flights](https://www.google.com/travel/flights) and returns **fares and flights as structured data**: one-way, round trip and multi-city legs, a **flexible-date price calendar**, **Google's own low / typical / high price verdict** with the usual price range, the **60-day price history** of the route and the best time to book. A **monitor mode** turns a scheduled run into a **flight price alert**: only the fares that dropped are returned and charged, and a webhook can post them to Slack or Discord.

It works as a **Google Flights API** alternative over plain HTTP: no browser, no account, no API key. The included datacenter proxy is enough; residential proxies only step in when Google refuses a search again and again, at no extra charge to you.

### Why use Google Flights Scraper?

Two things decide whether a Google Flights scraper gives you the truth, and both are measured.

**Google refuses searches without saying so.** From a datacenter IP, Google answers part of the searches with a normal-looking page (HTTP 200) whose results block is an error. A scraper that does not look for it returns "no flights" for a route that has plenty. We measured it on 50 searches from Apify servers on 18 October 2026:

| Same 50 searches | Answered on the first try | After retries on fresh IPs |
|---|---|---|
| One fixed datacenter IP | 30 / 50 | 48 / 50 |
| Apify datacenter proxy, new IP per try (this Actor) | 44 / 50 | **50 / 50** |

On a 200-search price calendar run the next day: 200 / 200 priced, 1.09 page requests per search. A search that still fails after every retry comes back as a free row marked `failed`, never as a silent "no flights".

**Google's results page shows a selection, not every flight.** On JFK to LAX the page lists 29 flights, all nonstop, while the same page names 14 airlines flying the route. Turn on **More results** and the Actor also searches each airline of the route and merges the flights: on three test routes it went from 60 to 109 flights. On the routes we checked, the cheapest fare was already on the main page, so you only need it for longer flight lists.

What you can do with it:

- **Fare monitoring and price alerts**: schedule a run every morning, get only the drops, or a ping when a route falls under your target price.
- **Price calendars**: cheapest fare for each of the next 30, 60 or 90 departure dates, with Google's verdict per date.
- **Travel apps and content**: route pages, deal newsletters, "is now a good time to book" widgets built on Google's verdict and history.
- **Market research**: airlines on a route, nonstop availability, fares by cabin and by date, CO2 per itinerary.

Every Apify feature applies: scheduling, API access, webhooks, integrations with Make, Zapier, n8n or Google Sheets, proxy rotation and run monitoring.

### What data can Google Flights Scraper extract?

The dataset has two kinds of rows. A **fare** row is one priced search (a route and its dates). A **flight** row is one flight option of that search.

| Field | Row | Description |
|---|---|---|
| `cheapestPrice` | fare | Cheapest fare for the search, all travellers, after your filters |
| `priceLevel` | fare | Google's verdict: `low`, `typical` or `high` |
| `typicalPriceLow` / `typicalPriceHigh` | fare | The price range Google considers usual for this trip |
| `priceHistory` | fare | Lowest fare of the route for this date, day by day over ~60 days |
| `cheapestBookingWindow` | fare | When this trip is usually cheapest to book (days before departure) |
| `airlinesOnRoute`, `nonstopAvailable` | fare | Airlines flying the route, nonstop or not |
| `previousPrice`, `priceChange`, `isPriceDrop` | fare | Monitor mode: what changed since the last run |
| `price`, `airlines`, `flightNumbers` | flight | Fare, airlines and flight numbers |
| `departureTime`, `arrivalTime`, `durationMinutes`, `stops` | flight | Schedule and connections |
| `legs`, `layovers` | flight | Each flight with aircraft, legroom, airports; each layover with its duration |
| `co2Grams`, `co2Label` | flight | Emissions estimate and how it compares to the route |
| `returnFlight` | flight | Round trips: the matching return flight |
| `bookingUrl` | flight | Google Flights page of that exact itinerary, with the airlines and agencies selling it |

### How to scrape Google Flights

1. Open the Actor and add one line per trip in **Searches**: `CDG JFK 2026-12-03 2026-12-10`. Codes are IATA airport codes (`JFK`, `LHR`) or city codes (`NYC`, `PAR`, `LON` cover every airport of the city).
2. Leave the dates out of a line to use **Depart in N days** and **Trip length** instead, the right choice for scheduled runs. For a single trip you can also use **From**, **To** and **Departure date**.
3. For a price calendar, set **Flexible dates** to the number of extra departure dates to price.
4. Set the cabin, travellers and filters you need.
5. Click **Start**, then download the results as JSON, CSV, Excel or HTML, or read them through the API.
6. For price alerts, save the input as a task, set **Monitor mode** to `drops` and schedule the task daily.

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

Pay per result, prices for the Apify Free plan (larger plans pay less, down to $0.0015 a fare and $0.0003 a flight):

| Event | Price |
|---|---|
| Run start | $0.002 |
| Fare (one priced search, one calendar date) | $0.003 |
| Flight (one flight row) | $0.0005 |

Searches with no flights, searches Google refused, unchanged fares in monitor mode and the multi-city total row are free.

Examples: one search with its ~20 flights costs about **$0.015**. A 30-day price calendar with fares only costs **$0.092**. Watching 50 routes every morning in `drops` mode costs $0.002 a day plus $0.003 per alert.

### Input

See the input tab for every option. The filters split in two groups. Stops, airlines, alliances, connecting airports and layover durations are applied by Google. Excluded airlines, maximum price, maximum duration and time windows are applied by the Actor to the flights Google returns, because Google ignores them on its side.

Example input for a round trip with return flights and a 14-day calendar:

```json
{
  "origin": "CDG",
  "destination": "JFK",
  "departureDate": "2026-12-03",
  "returnDate": "2026-12-10",
  "flexibleDays": 13,
  "maxStops": "1",
  "returnFlightsForTop": 2,
  "currency": "EUR"
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. A fare row and a flight row, shortened:

```json
[
  {
    "type": "fare",
    "tripType": "round-trip",
    "origin": "CDG",
    "destination": "JFK",
    "departureDate": "2026-12-03",
    "returnDate": "2026-12-10",
    "currency": "USD",
    "cheapestPrice": 545,
    "priceLevel": "typical",
    "typicalPrice": 684,
    "typicalPriceLow": 475,
    "typicalPriceHigh": 930,
    "savingsVsTypical": 139,
    "cheapestBookingWindow": {"from": "2026-05-17", "to": "2026-08-15", "daysBeforeDepartureFrom": 200, "daysBeforeDepartureTo": 110},
    "priceHistory": [{"date": "2026-08-19", "price": 612}, {"date": "2026-08-20", "price": 598}],
    "flightsFound": 18,
    "status": "ok"
  },
  {
    "type": "flight",
    "rank": 1,
    "price": 552,
    "currency": "USD",
    "priceIncludes": "round trip, all travellers",
    "airlines": ["AA"],
    "flightNumbers": ["AA 43"],
    "stops": 0,
    "durationMinutes": 500,
    "departureTime": "2026-12-03T11:25",
    "arrivalTime": "2026-12-03T13:45",
    "returnFlight": {"flightNumbers": ["AA 42"], "departureTime": "2026-12-10T18:00", "stops": 0},
    "bookingUrl": "https://www.google.com/travel/flights/booking?tfs=..."
  }
]
```

### Tips and advanced options

- **Fares only is the cheap setting.** Turn off **Include flight details** for calendars and monitoring: you get the cheapest price, the verdict and the history without paying for 20 flight rows per search.
- **Round trips**: Google prices a round trip on the outbound flight. The outbound rows carry the round-trip total. Set **Return flights for the top N** to get the actual return flights of the first N outbounds.
- **Multi-city**: Google serves multi-city fares only inside its own app. The Actor prices each leg as a one-way ticket and adds a free row with the sum of the cheapest legs.
- **Rolling dates in monitor mode**: with **Depart in N days**, the memory follows "N days ahead" from one run to the next, so a daily task alerts when the fare for a trip a month out drops. With fixed dates and **Flexible dates**, past dates are skipped and the task keeps running until the last date.
- **Monitor memory**: runs with the same searches share their memory automatically. Set **Monitor memory name** to share it between tasks or to start over.
- **Webhook**: the summary carries `text` and `content` fields, so a Slack or Discord incoming webhook URL works without any glue.
- **Calling it from code** (Python):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("alexmorain/google-flights-scraper").call(run_input={
    "searches": ["JFK LAX 2026-12-01", "SFO NRT 2026-12-05 2026-12-19"],
    "includeFlights": False,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["origin"], row["destination"], row["cheapestPrice"], row["priceLevel"])
```

### FAQ, disclaimers and support

#### Does it need a Google account, an API key or residential proxies?

No. It reads the public Google Flights results page over HTTP through Apify's datacenter proxy. If Google keeps refusing a search, the Actor retries it through residential proxies by itself, at no extra charge to you.

#### Why are there fewer flights than on the Google Flights website?

Google's page shows a selection and loads the rest when you click "more flights". Turn on **More results** to search each airline of the route as well. Booking options with every agency's price are loaded the same way and are not in the dataset: the `bookingUrl` opens that page.

#### How far ahead can I search?

From today up to 330 days ahead, like Google Flights. Dates outside that window are rejected before the run spends anything.

#### Is it legal to scrape Google Flights?

Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers. Google Flights results contain no personal data.

#### Something is wrong or missing

Open an issue in the Issues tab: it gets read and answered. For programmatic access, see the API tab.

# Actor input Schema

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

IATA airport or city code. Several codes separated by commas search them together, e.g. <code>JFK,EWR</code>. City codes such as <code>NYC</code>, <code>PAR</code> or <code>LON</code> cover every airport of the city. Use it for a single trip, or use <b>Searches</b> for one or many.

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

IATA airport or city code, same format as From.

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

YYYY-MM-DD. Google Flights prices dates from today up to 330 days ahead. Leave empty and use <b>Depart in N days</b> for a rolling date in scheduled runs.

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

YYYY-MM-DD. Set it for a round trip, leave it empty for one way. Round-trip prices are totals for both directions.

## `departureInDays` (type: `integer`):

Used for every search without a departure date: the departure is today plus N days. Handy for a daily schedule that always looks N days ahead; monitor mode then compares "30 days ahead" from one run to the next.

## `tripLengthDays` (type: `integer`):

Used when no return date is set: makes the search a round trip that comes back N days after departure.

## `flexibleDays` (type: `integer`):

Also search the next N departure dates (0 = only the date given). Each date gives one fare row with its cheapest price and Google's verdict, so 30 builds a month-long price calendar. Round trips keep the same trip length. Dates already in the past are skipped, so a scheduled calendar keeps working until its last date.

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

Trips to search, one line per trip: <code>ORIGIN DESTINATION \[DEPARTURE] \[RETURN]</code>, e.g. <code>CDG JFK 2026-12-03 2026-12-10</code>. A line without dates uses <b>Depart in N days</b> and <b>Trip length</b>. Through the API each item can also be an object with <code>origin</code>, <code>destination</code>, <code>departureDate</code>, <code>returnDate</code>, <code>departureInDays</code>, <code>tripLengthDays</code>, <code>label</code> and <code>targetPrice</code>.

## `multiCityLegs` (type: `array`):

2 to 6 legs, each an object with <code>origin</code>, <code>destination</code> and <code>date</code>. Google Flights only serves multi-city fares inside its own app, so each leg is priced as a separate one-way ticket and an extra free row adds up the cheapest fare of each leg (not returned in monitor mode).

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

Prices are totals for all travellers.

## `children` (type: `integer`):

Ages 2 to 11.

## `infantsInSeat` (type: `integer`):

Under 2, with their own seat.

## `infantsOnLap` (type: `integer`):

Under 2, on an adult's lap. One per adult.

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

Cabin for every flight of the trip.

## `maxStops` (type: `string`):

Applied by Google.

## `airlines` (type: `array`):

2-letter IATA codes, e.g. <code>DL</code>, <code>AF</code>. Google also keeps codeshare flights sold by these airlines.

## `alliances` (type: `array`):

Applied by Google, codeshares included.

## `excludeAirlines` (type: `array`):

2-letter IATA codes. Google ignores this filter on its side, so the Actor drops every flight with a leg on these airlines.

## `connectingAirports` (type: `array`):

IATA codes of the only airports allowed for layovers. Nonstop flights stay in.

## `minLayoverMinutes` (type: `integer`):

Shortest connection allowed, applied by Google.

## `maxLayoverMinutes` (type: `integer`):

Longest connection allowed, applied by Google.

## `maxPrice` (type: `integer`):

In the chosen currency, for all travellers.

## `maxDurationHours` (type: `integer`):

Total travel time of one direction, layovers included.

## `departureTimeFrom` (type: `integer`):

Local hour, 0 to 23. Applies to the outbound flight.

## `departureTimeTo` (type: `integer`):

Local hour, 0 to 23.

## `arrivalTimeFrom` (type: `integer`):

Local hour, 0 to 23. Applies to the outbound flight.

## `arrivalTimeTo` (type: `integer`):

Local hour, 0 to 23.

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

ISO code, e.g. <code>USD</code>, <code>EUR</code>, <code>GBP</code>.

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

Language of airport and airline names, e.g. <code>en</code>, <code>fr</code>, <code>de</code>.

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

2-letter country code of the market Google prices for, e.g. <code>US</code>, <code>GB</code>, <code>FR</code>.

## `includeFlights` (type: `boolean`):

On: one row per flight (airlines, times, legs, layovers, aircraft, CO2, booking link) next to each fare row. Off: fare rows only (cheapest price, Google's verdict, price history), the cheap setting for calendars and price monitoring.

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

0 = every flight Google lists on its results page (usually 10 to 35).

## `returnFlightsForTop` (type: `integer`):

Round trips only. Google prices a round trip on the outbound flight; set N to also fetch the matching return flights of the first N outbound flights. Each outbound costs one extra page and gives one row per outbound and return pair.

## `moreResults` (type: `boolean`):

Google's results page lists a selection of flights, not every one (JFK to LAX: 29 nonstop flights shown, while 14 airlines fly the route). On: the Actor also searches each airline of the route and merges the flights, about +40% flights for up to 15 extra pages per search. Ignored when airlines or alliances are set.

## `monitorMode` (type: `string`):

For scheduled runs. The Actor remembers the cheapest price of each search between runs.<br>• <b>off</b>: no memory.<br>• <b>all</b>: every fare row, with the previous price and the change.<br>• <b>changes</b>: only fares whose price moved since the last run.<br>• <b>drops</b>: only price drops (and fares under the target price). Unchanged searches are neither returned nor charged.

## `dropThresholdPercent` (type: `integer`):

Drops mode: ignore drops smaller than this percentage. 0 = any drop.

## `targetPrice` (type: `integer`):

Drops mode: also alert when the cheapest fare reaches this price or less, once per crossing.

## `monitorKey` (type: `string`):

Optional. Runs with the same searches share a memory on their own; set a name to share it between tasks with different inputs, or to start a fresh one.

## `webhookUrl` (type: `string`):

Optional. At the end of a run that returned something, the Actor POSTs a JSON summary with the alerts. It carries <code>text</code> and <code>content</code> fields, so a Slack or Discord incoming webhook URL works as is.

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

Apify Proxy (datacenter) is enough: Google refuses some searches per IP and the Actor retries them on a fresh IP. If a page is refused 5 times in a row, or the datacenter pool is mostly refused, the Actor retries through residential proxies at no extra charge to you.

## Actor input object example

```json
{
  "departureInDays": 30,
  "flexibleDays": 0,
  "searches": [
    "JFK LAX"
  ],
  "adults": 1,
  "children": 0,
  "infantsInSeat": 0,
  "infantsOnLap": 0,
  "cabinClass": "economy",
  "maxStops": "any",
  "currency": "USD",
  "language": "en",
  "country": "US",
  "includeFlights": true,
  "maxFlightsPerSearch": 0,
  "returnFlightsForTop": 0,
  "moreResults": false,
  "monitorMode": "off",
  "dropThresholdPercent": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with fare and flight rows.

# 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 = {
    "departureInDays": 30,
    "searches": [
        "JFK LAX"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("alexmorain/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 = {
    "departureInDays": 30,
    "searches": ["JFK LAX"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("alexmorain/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 '{
  "departureInDays": 30,
  "searches": [
    "JFK LAX"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call alexmorain/google-flights-scraper --silent --output-dataset

```

## MCP server setup

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