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

Google Flights scraper and flight price tracker: offers for any route and date with price, airlines, flight numbers, stops, duration, departure and arrival times, CO2 and the Best label. One way or round trip, any cabin. Monitor mode alerts when the cheapest price changes.

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

## Pricing

from $0.80 / 1,000 result items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Google Flights Scraper

Get Google Flights offers for any route and date as one flat row per flight: price, airlines, flight numbers,
stops, total duration, departure and arrival times and airports, layovers, CO2 estimate and whether Google lists
it among the "Best" flights. One way or round trip, any cabin and number of adults. It doubles as a **flight price
tracker**: monitor mode keeps the cheapest price of every route you save and alerts you only when it changes.

**Try it:** the prefilled example returns 20 rows in about 5 seconds and costs about $0.02. Results cost $1 per 1,000.

### What you get

Real rows from the example dataset (the prefilled route JFK to LHR, one way, 30 days ahead: 2026-12-01):

| airlines | flights | price | stops | minutes | departs | arrives | best | cheapest |
|---|---|---|---|---|---|---|---|---|
| British Airways | BA 178 | $300 | 0 | 415 | 2026-12-01 08:05 | 2026-12-01 20:00 | yes | no |
| JetBlue | B6 1107 | $300 | 0 | 434 | 2026-12-01 09:26 | 2026-12-01 21:40 | yes | no |
| Delta | DL 1 | $300 | 0 | 425 | 2026-12-01 20:00 | 2026-12-02 08:05 | yes | no |
| American | AA 104 | $300 | 0 | 420 | 2026-12-01 21:15 | 2026-12-02 09:15 | yes | no |
| Aer Lingus | EI 104, EI 152 | $298 | 1 | 605 | 2026-12-01 17:00 | 2026-12-02 08:05 | no | yes |

Full row: `id`, `url` (the Google Flights search), `route`, `from`, `to`, `departDate`, `returnDate`, `tripType`,
`adults`, `cabin`, `price`, `currency`, `airlines`, `flightNumbers`, `stops`, `durationMinutes`,
`departureAirport`, `departureTime`, `arrivalAirport`, `arrivalTime`, `layovers` (airport, minutes), `legs`
(flight number, airline, operator, airports, times, minutes, aircraft), `isBest`, `isCheapest`, `co2Grams`,
`co2TypicalGrams`, `co2DiffPercent`, `rank`, `routeKey`, `scrapedAt`.

Times are local to each airport, as on the departure board. `price` is the total for all adults; on a round trip
it is the round-trip total, as Google shows it.

### Use cases

- **Flight price tracker.** The main use: save your routes and dates in monitor mode, schedule it daily, and get
  a webhook or Telegram message only when the cheapest fare for a route goes up or down.
- **Fare research.** Compare many routes or dates in one run and sort by price, stops or duration in a
  spreadsheet.
- **Travel and deal sites.** Feed a deals page with today's cheapest nonstop fares from a list of airports.
- **Emissions reporting.** Use `co2Grams` per offer to compare the footprint of options on the same route.

### Try it in 10 seconds

**One-off search.** Press **Start**: the prefilled input searches JFK to London Heathrow one way, 30 days from
today. Add `departDate` and `returnDate` to a route for your own trip.

**Flight price tracker (monitor mode).** Save a task with this input and put it on a schedule (Apify, Schedules,
e.g. every morning):

```json
{
  "mode": "monitor",
  "monitorStateId": "christmas-trip",
  "routes": [
    {"from": "JFK", "to": "LHR", "departDate": "2026-12-20", "returnDate": "2027-01-03"},
    {"from": "WAW", "to": "BCN", "departDate": "2026-12-20"}
  ],
  "adults": 2,
  "webhookUrl": "https://your-endpoint.example.com/hook"
}
```

Monitor mode needs a fixed `departDate` on every route (a run without one stops before any request, because a
moving "30 days from today" date would never compare with the previous run). It returns one row per route, the
cheapest offer, and only when its price differs from the previous run
(or on the first run). Each monitor run charges one `monitor-check` event ($0.005) plus one `change` event ($0.001)
per route whose cheapest price moved. A run with no price change charges only the check.

### Related actors

- [Google Trends Scraper](https://apify.com/datahamster/google-trends-scraper): how interest in a destination moves
  over time.
- [Zillow Scraper](https://apify.com/datahamster/zillow-scraper): the same price-change monitor for US real estate
  listings.
- [Google News Scraper](https://apify.com/datahamster/google-news-feed): travel news about a destination or an
  airline, with alerts.

### Input

| Field | Meaning | Default |
|---|---|---|
| `routes` | List of `{from, to, departDate, returnDate?}` with IATA airport codes, dates up to 330 days ahead | `[{"from": "JFK", "to": "LHR"}]` |
| `adults` | Adult travellers, 1 to 9 | `1` |
| `cabin` | `economy`, `premium_economy`, `business`, `first` | `economy` |
| `currency` | Price currency, ISO code | `USD` |
| `language` / `country` | Google language and market | `en` / `US` |
| `maxStops` | Keep offers with at most this many stops | all |
| `cheapestOnly` | One row per route, the cheapest offer | `false` |
| `maxOffersPerRoute` | Offers per route | `100` |
| `maxItems` | Rows per run in total | `200` (prefilled 20) |
| `mode`, `monitorStateId`, `webhookUrl`, `telegramBotToken`, `telegramChatId` | Monitor mode and alerts | `scrape` |

### How it works

1. Each route is turned into the same encoded search link Google Flights builds when you search on the site
   (airports, dates, travellers, cabin, one way or round trip).
2. The results page is read from the data Google renders it from: the "Best" flights and the other departing
   flights, with prices in the currency you asked for.
3. Unknown airport codes make Google show its start page instead of results, and Google's own echo of the search
   then has no airports; such a route yields nothing and costs nothing. Any other page without offers is treated as a
   bot check.
4. If Google answers with a bot check, the request is retried on a stronger proxy tier. A run where every request
   was refused ends as **blocked**, never as an empty "no results".

### Pricing

| Event | Price |
|---|---|
| result | $0.001 per offer ($1 per 1,000) |
| monitor-check | $0.005 per monitor run |
| change | $0.001 per route whose cheapest price changed |

Store discounts: SILVER plan -10%, GOLD and above -20% on every event.

You pay only for rows that are pushed. Platform usage is billed by Apify on top; runs need no proxy.

### Limits

- A round-trip search lists the outbound flights with the round-trip total. Return-flight details are not
  included, because Google shows them only after an outbound flight is picked.
- Searches use airport codes (JFK, LHR). Metropolitan city codes such as NYC or LON are passed to Google as they are.
- Google shows about 20 to 40 offers per search; the actor returns that list and does not click "more flights".
- Prices are what Google shows for the market in `country`; airlines and booking sites may differ slightly.
- Children and infants cannot be added in this version.

### FAQ

**Does it need a Google account or an API key?** No. Every request is made as a logged-out visitor.

**How often should a price tracker run?** Daily is usual. Fares change several times a day on busy routes, so twice
a day catches more moves at twice the monitor-check cost.

**Why did a run return nothing?** The `RUN_SUMMARY` record in the run's key-value store has `emptyReason`. A bot
check is reported as `blocked`, a route with no offers or unknown airports as `no_matches`.

### Changelog

- 0.1: initial release. One way and round trip offers by route and date with airlines, flight numbers, stops, times,
  layovers and CO2; cheapest and Best flags; monitor mode as a flight price tracker.

***

If this actor saved you time, a short review on its Store page helps other people find it. Missing a field? Open an
issue on the **Issues** tab.

# Actor input Schema

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

Stop the whole run after this many rows. You are charged only for rows pushed.

## `mode` (type: `string`):

scrape = full results; monitor = only new/changed items since the previous run of this task

## `monitorStateId` (type: `string`):

Optional state id when not running as a saved task (monitor mode)

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

POST a change summary here in monitor mode

## `telegramBotToken` (type: `string`):

Optional: bot token for monitor-mode change summaries

## `telegramChatId` (type: `string`):

Optional: chat id that receives monitor-mode summaries

## `routes` (type: `array`):

One object per search: `from` and `to` as 3-letter IATA airport codes, `departDate` as YYYY-MM-DD and an optional `returnDate` for a round trip. Example: \[{"from": "JFK", "to": "LHR", "departDate": "2026-12-11", "returnDate": "2026-12-18"}]. Without `departDate` the search is 30 days from today, which keeps a saved scrape task valid; monitor mode needs a fixed `departDate`. Dates up to 330 days ahead.

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

Number of adult travellers. Prices are the total for all of them.

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

Cabin class to search.

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

ISO currency code for prices, e.g. USD, EUR, GBP, PLN. Every row carries the currency Google priced it in.

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

Google interface language code for airport and airline names, e.g. "en", "de".

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

Two-letter country code of the market Google shows prices for (Google's `gl`), e.g. US, GB, DE.

## `maxStops` (type: `integer`):

Keep only offers with at most this many stops. 0 = nonstop only. Empty keeps all.

## `cheapestOnly` (type: `boolean`):

Return one row per route: the cheapest offer. Monitor mode always works this way.

## `maxOffersPerRoute` (type: `integer`):

Stop after this many offers per route. Google lists about 20 to 40 offers per search.

## Actor input object example

```json
{
  "maxItems": 20,
  "mode": "scrape",
  "routes": [
    {
      "from": "JFK",
      "to": "LHR"
    }
  ],
  "adults": 1,
  "cabin": "economy",
  "currency": "USD",
  "language": "en",
  "country": "US",
  "cheapestOnly": false,
  "maxOffersPerRoute": 100
}
```

# Actor output Schema

## `results` (type: `string`):

All pushed rows (dataset, JSON)

## `resultsTable` (type: `string`):

Dataset in the Console viewer

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

RUN_SUMMARY record

# 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 = {
    "maxItems": 20,
    "routes": [
        {
            "from": "JFK",
            "to": "LHR"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahamster/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 = {
    "maxItems": 20,
    "routes": [{
            "from": "JFK",
            "to": "LHR",
        }],
}

# Run the Actor and wait for it to finish
run = client.actor("datahamster/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 '{
  "maxItems": 20,
  "routes": [
    {
      "from": "JFK",
      "to": "LHR"
    }
  ]
}' |
apify call datahamster/google-flights-scraper --silent --output-dataset

```

## MCP server setup

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