# Google Flights Scraper – Airfare Data, $0.80/1,000 Flights (`griffie/google-flights-scraper`) Actor

Turn a list of routes into a sheet of live Google Flights fares. Every row is one flight with its price, airline, flight number, local times, stops, layover airports and CO2. Pair origins with destinations, scan up to 60 departure dates, pull return legs. Searches with no fares cost nothing.

- **URL**: https://apify.com/griffie/google-flights-scraper.md
- **Developed by:** [Dustin Griffie](https://apify.com/griffie) (community)
- **Categories:** Travel, Agents, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 flights

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

## Google Flights Scraper: airfare data at $0.80 per 1,000 flights

Give this Actor a few routes, or a few hundred, and it hands back Google Flights results as tidy rows you can sort, filter and chart. Each flight comes with what you would check before booking: the fare, the airline and flight number, when it leaves and lands in local time, how long it takes, where it stops and how much CO2 it burns compared with the usual flight on that route. Times come in local and UTC, and each flight lists its codeshare numbers, onboard Wi-Fi and power, and a link to its Google Flights booking page. A price calendar mode prices every departure day for up to 330 days in a single call per route. It runs on plain HTTP with no browser, and you pay only when a flight lands in your dataset.

### What does this Google Flights scraper do?

You describe trips; the Actor asks Google Flights about each one and writes down what comes back.

A **search** is one route on one departure date (plus a return date for round trips). You can feed searches in three ways, and mix them:

- **Routes** such as `SEA-LAX`, `JFK-LHR` or `NYC-TYO`. City codes (`NYC`, `LON`, `PAR`, `TYO`) cover every airport in that metro area.
- **Origins × destinations.** List 3 origins and 4 destinations and you get all 12 pairs without typing them out.
- **Date ranges.** Pick a first date (a fixed day or "N days from today"), how many dates to try (up to 60) and the gap between them. A 30-day scan of one route is 30 searches.

For every search the Actor:

1. Asks Google Flights' own data feed (the one its web app uses) for the whole flight list of that trip. On our test routes that is 70–200 flights in about half a second.
2. If Google declines that request, it tries again from a fresh IP a few times, then falls back to reading the results page plus one airline-filtered page per carrier and merging them. That fallback is slower and finds fewer flights (35–60 on busy routes). Each row's `source` field says which way it was collected. Duplicates are dropped either way, so a flight never appears (or bills) twice.
3. For round trips, picks the cheapest outbound options and fetches the return flights that pair with them.
4. Writes one row per flight, plus one free summary row per search with the cheapest fare, Google's verdict on the price, the usual price band and Google's daily fare history for roughly the last two months.

Switch `mode` to `calendar` and the job changes: each route returns one row per departure day with the cheapest fare Google knows for that day, up to 330 days ahead, and round trips use a fixed stay length.

Rows come out as JSON, CSV, Excel, XML or HTML from the dataset tab, or straight through the Apify API.

### Which flight data do I get?

There are three kinds of rows, told apart by `recordType`.

#### Flight rows (`recordType: "flight"`, billed)

| Field | What it holds |
|---|---|
| `price`, `currency`, `priceType` | Total fare for all passengers you entered. `priceType` says whether it is a one-way or round-trip total. |
| `airlines`, `flightNumbers` | Every carrier and flight number on the itinerary, e.g. `["UA 1833", "UA 1583"]`. |
| `departureAirport`, `arrivalAirport` | IATA codes of the first and last airport. |
| `departureTime`, `arrivalTime` | Local times at each airport, ISO format without offset (`2026-12-04T08:00`). |
| `departureTimeUtc`, `arrivalTimeUtc`, `departureUtcOffset`, `arrivalUtcOffset`, `departureTimeZone`, `arrivalTimeZone` | The same moments in UTC, with each airport's offset and IANA zone, worked out offline from a built-in table of about 7,900 airports (daylight saving included). `null` for the rare airport missing from the table. |
| `durationMinutes`, `duration` | Door-to-door time, as minutes and as text. |
| `stops`, `layoverAirports`, `layovers` | Stop count, the connecting airports and each layover's length. |
| `emissionsKg`, `typicalEmissionsKg`, `emissionsDiffPercent` | Google's CO2 estimate for this itinerary and for a typical one on the route. |
| `aircraft`, `operatedBy` | Plane types and the carrier actually flying the plane, when it differs. |
| `codeshareFlightNumbers` | Other airlines' numbers sold on the same flights, e.g. `["AF 9656", "DL 5996"]`. |
| `wifiOnAllLegs`, `powerOnAllLegs`, `inSeatVideoOnAllLegs` | `true` when Google lists Wi-Fi, seat power or a seatback screen on every segment. `false` means Google did not list it, not that the plane surely lacks it. |
| `bookingUrl` | Opens this exact itinerary on Google Flights' booking page, where the airline and agency offers are listed. Filled on one-way rows and round-trip return rows (both directions are known there). |
| `pricePerAdult` | `price` divided by the number of adults, when every passenger is an adult; otherwise `null`. |
| `legs` | One entry per flight segment with airport names, local and UTC times, airline code, aircraft, legroom, codeshares, an `amenities` object (`wifi`: free/paid, `power`: outlet/USB, `video`, `seatType`) and segment CO2 (turn off with `includeLegs`). |
| `resultRank`, `isBestFlight` | Position in Google's order, and whether Google flagged it as a "best" pick. |
| `source`, `listSource` | How the row was collected: `api` (Google's full list, `listSource: "full_list"`), `page` or `page_airline_fanout` (results page, `listSource` `results_page` or `airline_filter`). |
| `priceLevel`, `lowestPriceForSearch`, `typicalPriceLow`, `typicalPriceHigh` | Google's price insight for this search, copied onto every row so a flat CSV is still useful. |
| `legType`, `returnDate`, `outboundFlightNumbers`, `outboundPrice` | For round trips: `outbound` or `return`, and on return rows the outbound flight (numbers, airlines, times, stops) they pair with. |
| `googleFlightsUrl` | Opens the same search on Google Flights. |
| search inputs | `origin`, `destination`, `departureDate`, `cabinClass`, passengers, `country`, `scrapedAt`. |

Here is a real nonstop row from a run on 4 Nov 2026 (legs trimmed to one):

```json
{
  "recordType": "flight",
  "route": "JFK-LHR",
  "price": 300,
  "currency": "USD",
  "priceType": "one way total for 1 passenger(s)",
  "resultRank": 1,
  "isBestFlight": true,
  "source": "api",
  "listSource": "full_list",
  "pricePerAdult": 300,
  "airlines": ["Virgin Atlantic"],
  "flightNumbers": ["VS 26"],
  "codeshareFlightNumbers": ["AF 9656", "DL 5996", "KL 2505"],
  "departureTime": "2026-12-04T08:00",
  "arrivalTime": "2026-12-04T20:10",
  "departureTimeUtc": "2026-12-04T13:00:00Z",
  "arrivalTimeUtc": "2026-12-04T20:10:00Z",
  "duration": "7 hr 10 min",
  "stops": 0,
  "emissionsKg": 369,
  "typicalEmissionsKg": 434,
  "emissionsDiffPercent": -15,
  "aircraft": ["Airbus A330-900neo"],
  "wifiOnAllLegs": true,
  "powerOnAllLegs": true,
  "legs": [{ "flightNumber": "VS 26", "aircraft": "Airbus A330-900neo", "legroom": "31 inches",
             "amenities": { "wifi": "paid", "power": "outlet_and_usb", "video": "on_demand", "seatType": "average" } }],
  "priceLevel": "typical",
  "typicalPriceLow": 170,
  "typicalPriceHigh": 470,
  "bookingUrl": "https://www.google.com/travel/flights/booking?tfs=…",
  "cabinClass": "economy",
  "departureDate": "2026-12-04"
}
```

#### Search summary rows (`recordType: "search"`, never billed)

One per search, turned on by `includeSearchSummary`. Searches that fail, find nothing or are invalid always get one, so you can see what happened to every search in the same table.

| Field | What it holds |
|---|---|
| `status`, `statusMessage` | `ok`, `no_results`, `invalid`, `failed`, or a max-cost stop, with a plain-English reason. |
| `flightsFound`, `flightsSaved`, `nonstopFlights`, `airlinesFound` | How big the route is. |
| `cheapestPrice`, `cheapestAirlines`, `cheapestFlightNumbers`, `cheapestDepartureTime`, `cheapestStops` | The best fare in one place. |
| `priceLevel` | Google's label: `low`, `typical` or `high`. |
| `usualPrice`, `typicalPriceLow`, `typicalPriceHigh` | The price band Google considers normal for this trip. |
| `priceHistory` | About 61 daily points (`{date, price}`) for the lowest fare on this exact search over the last two months. |
| `priceHistoryMin`, `priceHistoryMax`, `priceHistoryDays`, `priceHistoryFirstDate`, `priceHistoryLastDate` | That history condensed into numbers you can filter on. |
| `source`, `apiAttempts`, `extraPagesFetched` | Which method served the search, how many data-feed requests it took, and how many airline-filtered pages the fallback opened. |

From the same run, trimmed to the last three history points:

```json
{
  "recordType": "search",
  "route": "JFK-LHR",
  "departureDate": "2026-12-04",
  "status": "ok",
  "flightsFound": 108,
  "nonstopFlights": 19,
  "cheapestPrice": 298,
  "cheapestAirlines": ["Aer Lingus"],
  "cheapestFlightNumbers": ["EI 104", "EI 152"],
  "priceLevel": "typical",
  "usualPrice": 298,
  "typicalPriceLow": 170,
  "typicalPriceHigh": 470,
  "priceHistoryDays": 61,
  "priceHistoryMin": 291,
  "priceHistoryMax": 321,
  "priceHistory": [
    { "date": "2026-11-02", "price": 298 },
    { "date": "2026-11-03", "price": 298 },
    { "date": "2026-11-04", "price": 298 }
  ],
  "source": "api",
  "apiAttempts": 1,
  "charged": false
}
```

#### Price calendar rows (`recordType: "calendar-day"`, calendar mode)

Set `mode` to `calendar` and `calendarDays` to how many departure days you want (1–330). Each route then gives one row per day that Google has a price for, plus a summary row with `cheapestDate`, `cheapestPrice`, `highestPrice`, `medianPrice` and `daysWithPrice`. It works for single journeys and for return trips, which keep the stay fixed at `tripLengthDays`. Stops, airline, cabin and passenger filters apply. A 330-day calendar took a few seconds per route in our runs. Each saved day costs $0.0001, so 60 days is $0.006 and a full 330 days $0.033 per route; days Google has no price for are not saved and cost nothing. Google's calendar stops about 330 days from today, and the exact last day can shift by one around midnight. If your range runs past it, the Actor ends the range on Google's last day instead of failing, and the summary row shows `rangeShortenedToGoogleLimit: true` with the dates it covered.

A real row from 4 Nov 2026:

```json
{
  "recordType": "calendar-day",
  "route": "JFK-LHR",
  "tripType": "one_way",
  "departureDate": "2026-11-25",
  "dayOfWeek": "Wed",
  "price": 304,
  "currency": "USD",
  "isCheapestDay": false,
  "priceVsCheapestPercent": 18.8,
  "charged": true
}
```

The same run's summary row found the cheapest day 144 days out: $256 on 29 March 2027, against a median of $300 across the 330 days.

The dataset has five views: **Flights** (one line per flight), **Search summary & price history**, **Price calendar**, **Price by date** (handy for date scans) and **Legs, layovers & price insights** (segments, UTC times, codeshares, amenities, booking links). Filter on `recordType` when you export if you want only one kind.

### Ready-to-run examples

Each of these is a saved task you can open, tweak and run. All of them use relative dates, so they keep working on a schedule.

| Task | What it shows |
|---|---|
| [Cheapest departure day: scan 30 days of fares on one route](https://apify.com/griffie/google-flights-scraper/examples/cheapest-departure-day-30-day-scan) | One route for each of the next 30 days, cheapest flights plus a daily summary |
| [Transatlantic round trips priced with their return flights](https://apify.com/griffie/google-flights-scraper/examples/transatlantic-round-trips-with-returns) | NYC and Boston to London, Paris and Dublin, ten nights, with return legs |
| [Long-haul business class fares to watch every week](https://apify.com/griffie/google-flights-scraper/examples/business-class-long-haul-fare-watch) | Four long-haul business routes with aircraft and legroom per segment |
| [Nonstop flights for every origin × destination pair](https://apify.com/griffie/google-flights-scraper/examples/nonstop-route-grid-origins-destinations) | Three origins × three destinations, nonstop only |
| [Fares from one home airport to a dozen popular cities](https://apify.com/griffie/google-flights-scraper/examples/one-airport-to-many-cities-fares) | One home airport to 12 cities; cheapest fare and usual band per city |
| [Seven-night round trips, one departure a week for 8 weeks](https://apify.com/griffie/google-flights-scraper/examples/seven-night-trips-weekly-departures) | Eight weekly departure dates for a week-long round trip |
| [Cheapest fare calendar: every day for the next 6 months](https://apify.com/griffie/google-flights-scraper/examples/cheapest-fares-calendar-6-months) | Lowest one-way fare for every day over six months on three routes |
| [Cheap flights under a set price from one city](https://apify.com/griffie/google-flights-scraper/examples/cheap-flights-under-a-price-cap) | Only fares under a set price from one city to several destinations |
| [Round-trip fares for two adults and two kids](https://apify.com/griffie/google-flights-scraper/examples/family-of-four-round-trip-fares) | Two adults and two kids as one booking, with return flights |
| [Lowest round-trip fare for every departure day, 11 months out](https://apify.com/griffie/google-flights-scraper/examples/round-trip-fare-calendar-full-year) | Lowest round-trip fare for every departure day, 11 months out |

A minimal input of your own looks like this:

```json
{
  "routes": ["SEA-LAX", "JFK-LHR"],
  "departureInDays": 21,
  "numberOfDates": 7,
  "maxStops": "1",
  "maxResultsPerSearch": 100
}
```

That is 14 searches: two routes on seven consecutive dates, three weeks out, at most one stop.

### Scraping Google Flights in three steps

1. **Say where and when.** Fill in `routes` (or `origins` and `destinations`), then either a `departureDate` or `departureInDays`. Round trip? Switch `tripType` to `round_trip` and add a `returnDate` or a `tripLengthDays`.
2. **Narrow it down if you like.** `maxStops`, `cabinClass` (from economy up to first), `airlines` (two-letter codes to keep), `maxPrice`, passengers (`adults`, `children`, `infantsInSeat`, `infantsOnLap`), `currency` and `country`. Country matters: Google shows a slightly different market for `gb` than for `us`.
3. **Run it and export.** Press Start, wait for the status line to count up, then download from the Output tab or read the dataset through the API.

A few settings change what you get back:

- `mode` picks `flights` (default) or `calendar`; `calendarDays` sets the calendar's length.
- `completeResults` (default on) asks for the route's full list. Turn it off to get only the shortlist on Google's first results page, which also keeps each search to a single page request.
- `searchMethod` is `auto` (data feed first, page fallback) or `page` (always the slower results-page method).
- `maxResultsPerSearch` (default 100, max 500) caps flight rows per search. Rows follow Google's order, so a cap of 20 keeps the 20 Google ranks highest. Busy routes often have more than 100 flights in the full list; raise the cap to get them all, or lower it to pay for fewer.
- `returnFlightsForCheapestOutbound` (1 to 10) decides how many outbound picks get their return flights looked up.
- `includeSearchSummary` adds the free summary row; `includeLegs` adds the per-segment detail.

### Watching airfare on a schedule

Fares move several times a day, and the useful question is usually "is this cheaper than it was?". Two features make that easy.

**Relative dates.** Use `departureInDays` instead of a fixed date. A daily schedule with `departureInDays: 30` always checks the trip a month out, so the series compares like with like.

**History in every run.** The summary row already carries about 60 days of Google's own price history for that search, plus the `low / typical / high` label. A single run tells you whether today's fare is near the bottom of its recent range, without you having collected anything beforehand.

To set it up, save your input as a task, open **Schedules** in Apify Console and pick a cron (daily at 06:00, every Monday, whatever suits). Point a webhook or an integration at the run's dataset and you can push new rows to Google Sheets, Slack, a database or email. A simple alert rule: notify when `cheapestPrice` is below `typicalPriceLow`, or when `priceLevel` turns `low`.

Scheduling costs nothing extra. Each scheduled run is billed like any other, by flights saved.

### What a run costs

You pay per flight row saved to the dataset, per day saved in calendar mode, and a tiny fee each time the Actor starts. Summary rows, empty searches, invalid searches, failed searches and failed calendars are free.

| Your Apify plan | Per flight row | Per 1,000 flights | Per calendar day | Actor start |
|---|---|---|---|---|
| Free | $0.0008 | $0.80 | $0.0001 | $0.00005 |
| Starter | $0.0007 | $0.70 | $0.0001 | $0.00005 |
| Scale | $0.0006 | $0.60 | $0.0001 | $0.00005 |
| Business | $0.0005 | $0.50 | $0.0001 | $0.00005 |

Some sums, on the Free plan:

- One domestic route on one date at the default cap of 100 flights (our busy test routes all reached it): about 8 cents. With `maxResultsPerSearch: 40`, about 3 cents.
- A price calendar for one route: 60 days $0.006, the full 330 days $0.033.
- The same route checked for 30 dates with `maxResultsPerSearch: 10`: 300 flights, about 24 cents.
- A daily watch of 5 routes keeping the top 20 each: 100 flights a day, about $2.40 a month.

You stay in control of the bill. `maxResultsPerSearch` caps every search. **Max cost per run** in the run options is respected too: when the budget runs low, the Actor stops early, saves only what fits and marks the affected searches or calendars `partial_max_cost` or `stopped_max_cost` in their summary rows. Rows that weren't saved are never charged. Proxy traffic and compute are included in the price.

### Calling it from code, n8n, Make or an AI agent

Anything you can click in Console you can also script. A Python example:

```python
import os
from apify_client import ApifyClient

apify = ApifyClient(os.environ["APIFY_TOKEN"])
payload = {"routes": ["BOS-SAN"], "departureInDays": 21, "maxResultsPerSearch": 50}
finished = apify.actor("griffie/google-flights-scraper").call(run_input=payload)

rows = apify.dataset(finished["defaultDatasetId"]).list_items().items
flights = [r for r in rows if r["recordType"] == "flight"]
summary = next(r for r in rows if r["recordType"] == "search")
print(len(flights), "flights; cheapest", summary["cheapestPrice"], summary["priceLevel"])
```

The JavaScript client (`apify-client`) works the same way. For a one-shot HTTP call, POST your input JSON to `https://api.apify.com/v2/acts/griffie~google-flights-scraper/run-sync-get-dataset-items` with your token, and the response body is the result rows.

**No-code tools.** n8n, Make and Zapier all have Apify modules: choose "Run Actor", pick this one, paste your input and map the dataset fields onward. **AI agents.** Apify's MCP server exposes this Actor as a tool, which lets an assistant such as Claude or Cursor run it ("find me nonstop fares from SFO to Tokyo next month") and read the rows back. Keep `maxResultsPerSearch` modest for agents so the answer fits in context; the summary row alone is often enough.

Planning the hotel too? The sister Actor [Google Hotels Prices Scraper](https://apify.com/griffie/google-hotels-prices-scraper) returns nightly rates for the same kind of bulk city and date list.

### Limits worth knowing

- **The data feed is not always available.** Google answers it from some IPs and declines from others. The Actor retries on fresh IPs with pauses between tries, and if Google keeps declining across a run it stops asking and uses the results-page method for the rest. That keeps the run going, at about 20 times the time per search and with fewer flights. Calendar mode has no page fallback, so a calendar that is still declined after several tries gets a `failed` summary row and costs nothing.
- **Speed.** In our 20-search tests on 4 Nov 2026 (512 MB) every search was served by the data feed. A run of 7 one-way searches took 4–16 seconds, depending on how often Google declined the first try, and 6 round trips with their returns took 8–12 seconds. A fallback search takes 15–60 seconds.
- **Booking links, not seller prices.** `bookingUrl` opens Google's booking page for the itinerary, where the airline and agencies are listed. The Actor does not read those individual offers.
- **City codes.** Common metro codes (`NYC`, `LON`, `PAR`, `TYO`, `CHI`, `WAS` and about 15 more) go through the data feed. Other city codes use the results-page method.
- **Children and infants.** On some routes Google returns fewer fares, or none, once children or lap infants are added. Try adults only if a search comes back empty.
- **No multi-city yet.** One-way and round trips only.
- **Prices are a snapshot.** Fares can change between the run and a booking, and Google sometimes shows slightly different prices by country and currency.

### FAQ

**Are prices per person?**
`price` is the total for everyone you entered, as Google shows it, and `priceType` says so. When all passengers are adults, `pricePerAdult` gives the per-person figure. With children or infants their fares differ, so it is left empty.

**How do round trips work?**
Outbound rows carry the round-trip total. The Actor then takes the cheapest outbound options (how many is up to you) and fetches the returns for each. Each return row repeats the full itinerary's total and names its outbound flight.

**How do I find the cheapest day to fly?**
Use calendar mode: `"mode": "calendar"` with `calendarDays: 90` gives up to 90 rows, one per day, for $0.009, and the summary row names the cheapest. Sixty days costs $0.006 and the full 330 days $0.033 per route. When you also want the flights behind each day, use a date range instead (`numberOfDates: 30`, `dateStepDays: 1`) and sort the summary view by `cheapestPrice`.

**How many flights per search?**
Up to `maxResultsPerSearch`, which is 100 unless you change it. In our 4 Nov 2026 test of 20 searches with the cap raised to 200, domestic routes averaged about 155 flights per search, long-haul ones about 118 and round trips about 91 (outbound plus returns). With the page method alone the same routes gave 37–44.

**Does it need residential proxies?**
No. It runs on Apify's datacenter proxy by default and retries on fresh IPs when Google hesitates. A residential fallback switch exists for unusually strict runs.

**Can I change currency and market?**
Yes. `currency` takes any ISO code (`EUR`, `GBP`, `JPY`) and `country` a two-letter market (`de`, `gb`, `jp`).

**Are times local?**
`departureTime` and `arrivalTime` are local at each airport, as Google shows them, so a red-eye can arrive "earlier" than it left. `departureTimeUtc` and `arrivalTimeUtc` give the same moments in UTC, so you can sort or subtract them directly.

**What happens with a typo in an airport code?**
That search gets a free summary row with status `no_results` or `invalid` and a short explanation; the rest of the run carries on.

### Is scraping Google Flights legal?

The Actor reads only public fare and schedule information, the same thing anyone sees on Google Flights, and collects no personal data. Even so, you are responsible for how you use the results: check Google's terms and the rules in your country, and ask a lawyer if your use case is unusual. Questions, odd routes or a missing field? Tell us in the Issues tab and we'll look into it.

# Actor input Schema

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

<b>Flights</b>: one row per flight for each route and date. <b>Price calendar</b>: one row per departure day with that day's lowest fare, for up to 330 days from the first departure date — the quickest way to find the cheapest day to fly. Each saved calendar day costs $0.0001 (60 days = $0.006, 330 days = $0.033 per route).

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

One route per line as <code>ORIGIN-DESTINATION</code> with 3-letter IATA codes, e.g. <code>SEA-LAX</code>, <code>JFK-LHR</code>. City codes search every airport in the city: <code>NYC-LON</code>, <code>TYO-SEL</code>. <code>SEA>LAX</code> and <code>SEA to LAX</code> also work. Each route × date is one search.

## `origins` (type: `array`):

Optional. Airport or city codes to combine with <b>Destinations</b>: every origin × destination pair is searched, e.g. 3 origins × 4 destinations = 12 routes.

## `destinations` (type: `array`):

Optional. Airport or city codes paired with every code in <b>Origins</b>.

## `tripType` (type: `string`):

Round trip prices are the total for outbound + return, as Google shows them.

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

Fixed date (YYYY-MM-DD). Leave empty to use <b>Departure in days</b> instead, so saved tasks and schedules never go stale.

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

Used when <b>Departure date</b> is empty: 14 = two weeks from the day the run starts.

## `numberOfDates` (type: `integer`):

Search several departure dates in one run to find the cheapest day to fly: 7 = the start date and the next 6 days (with step 1).

## `dateStepDays` (type: `integer`):

Gap between the departure dates above, e.g. 7 for the same weekday each week.

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

Fixed return date (YYYY-MM-DD). Leave empty to use <b>Trip length</b>.

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

Return = departure + this many days, when no fixed return date is given.

## `calendarDays` (type: `integer`):

Price calendar mode only: how many consecutive departure days to price, starting at the departure date. Round trips use <b>Trip length</b> as the fixed stay. Google's calendar ends about 330 days from today; a longer range is shortened to Google's last day and the summary row says so (<code>rangeShortenedToGoogleLimit</code>).

## `returnFlightsForCheapestOutbound` (type: `integer`):

Round trip only. Google lists return flights only after you choose an outbound flight. The Actor does that for the N cheapest outbound options and adds the return flights as <code>legType: "return"</code> rows (one extra request each). 0 = outbound list only.

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

Prices are the total for all passengers.

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

Children aged 2–11.

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

Infants under 2 with their own seat.

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

Infants under 2 on an adult's lap (max one per adult).

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

Economy, premium economy, business or first.

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

Limit the number of stops (applies to outbound and return).

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

Optional. Only these airlines: 2-letter IATA codes (<code>UA</code>, <code>DL</code>, <code>BA</code>) or an alliance: <code>STAR_ALLIANCE</code>, <code>ONEWORLD</code>, <code>SKYTEAM</code>.

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

Optional price cap in the chosen currency (0 = no cap).

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

3-letter ISO code: USD, EUR, GBP, AUD, JPY…

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

2-letter country code for the Google market prices come from, e.g. us, gb, de, au. Fares can differ by market.

## `completeResults` (type: `boolean`):

Return as much of the route's flight list as possible. In Auto mode the full list comes from Google's data feed; when it falls back to results pages, the Actor also opens one page per airline in Google's filter panel and merges the extra flights (de-duplicated). No fee for extra pages or calls: you pay only for the flight rows you keep (cap them with <b>Max flights per search</b>). Turn off for Google's shortlist only.

## `maxResultsPerSearch` (type: `integer`):

Upper limit of flight rows per search (and per return lookup). With <b>Complete flight list</b> on, a busy route often has more than 100 flights. You pay per flight row, so lower this to keep only the top of the list: Google's own order first, then the extra flights cheapest first.

## `searchMethod` (type: `string`):

<b>Auto</b> asks Google Flights' own data feed for the route's full flight list in one call and falls back to reading the results pages when Google declines. <b>Results pages only</b> always uses the page method (slower, fewer flights). Each row's <code>source</code> field shows which method served it.

## `includeSearchSummary` (type: `boolean`):

Adds one free row per search (<code>recordType: "search"</code>): cheapest flight, Google's price level and typical range, and the 60-day price history. Never charged. Searches with no results or errors always get this row.

## `includeLegs` (type: `boolean`):

Adds a <code>legs</code> array with each segment's flight number, aircraft, legroom, times and emissions.

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

The default Apify datacenter proxy works. Google sometimes answers with a temporary error page, and the Actor retries those on a new IP automatically.

## `fallbackToResidential` (type: `boolean`):

Switch to Apify RESIDENTIAL proxy if Google keeps blocking the datacenter IPs. Off by default because it is rarely needed.

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

Parallel searches. 4 is a good balance; lower it if you see many retries.

## `maxRetries` (type: `integer`):

Retries per search on a new IP when Google answers with a temporary error page or blocks.

## `debugLog` (type: `boolean`):

Verbose log for troubleshooting.

## Actor input object example

```json
{
  "mode": "flights",
  "routes": [
    "SEA-LAX",
    "JFK-LHR"
  ],
  "tripType": "one_way",
  "departureInDays": 14,
  "numberOfDates": 1,
  "dateStepDays": 1,
  "tripLengthDays": 7,
  "calendarDays": 60,
  "returnFlightsForCheapestOutbound": 1,
  "adults": 1,
  "children": 0,
  "infantsInSeat": 0,
  "infantsOnLap": 0,
  "cabinClass": "economy",
  "maxStops": "any",
  "maxPrice": 0,
  "currency": "USD",
  "country": "us",
  "completeResults": true,
  "maxResultsPerSearch": 100,
  "searchMethod": "auto",
  "includeSearchSummary": true,
  "includeLegs": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "fallbackToResidential": false,
  "maxConcurrency": 4,
  "maxRetries": 8,
  "debugLog": false
}
```

# Actor output Schema

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

Price, airlines, flight numbers, times, duration, stops, layovers and emissions.

## `searches` (type: `string`):

One free row per search: cheapest flight, price level, typical range and 60-day price history.

## `calendar` (type: `string`):

Calendar mode: the lowest fare for each departure day.

## `details` (type: `string`):

Per-segment details, layovers and Google's typical price range.

## `runStats` (type: `string`):

Searches per status, flights, retries, bytes and per-search timings.

# 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 = {
    "mode": "flights",
    "routes": [
        "SEA-LAX",
        "JFK-LHR"
    ],
    "tripType": "one_way",
    "departureInDays": 14,
    "currency": "USD",
    "maxResultsPerSearch": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("griffie/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 = {
    "mode": "flights",
    "routes": [
        "SEA-LAX",
        "JFK-LHR",
    ],
    "tripType": "one_way",
    "departureInDays": 14,
    "currency": "USD",
    "maxResultsPerSearch": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("griffie/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 '{
  "mode": "flights",
  "routes": [
    "SEA-LAX",
    "JFK-LHR"
  ],
  "tripType": "one_way",
  "departureInDays": 14,
  "currency": "USD",
  "maxResultsPerSearch": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call griffie/google-flights-scraper --silent --output-dataset

```

## MCP server setup

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