# Google Flights Scraper (`boncross/google-flights-search`) Actor

Scrape Google Flights for any route and date and get every itinerary with price, airlines, flight numbers, aircraft, legroom, layovers, CO2 and contrail warming, plus route price history and what changed since your last run. There is no proxy to set up and no proxy charge. $0.20 per 1,000 flights.

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

## Pricing

from $0.14 / 1,000 flight-scrapeds

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

### What is Google Flights Scraper?

Google Flights Scraper gets you the whole result list for a route and date: around 90 to 120 itineraries per search, where the page itself opens on a handful. Give it an origin, a destination and a date, or paste a Google Flights URL, and you get each itinerary back as structured data, leg by leg.

What sets it apart:

- You get the full list, quickly. Eight routes returned 1,122 itineraries in 5 to 7 seconds, and 300 routes finished in 31 seconds.
- Sorting works on the complete list. Ask for cheapest first and you get the cheapest of all 100-odd itineraries, not of a first page.
- It reads the contrail warming potential of each leg, which most flight data leaves out, next to CO2 per leg and against the route's typical.
- Price context arrives with the search: about two months of daily price history, the typical and lowest fare, and how each itinerary's price moved since your last run.
- One price and nothing to set up. $0.20 per 1,000 flights on the Free plan and $0.14 on Business, with proxy usage and platform usage included.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 46 of 46 live checks on its inputs and filters passed on 8 October 2026
- 8 varied routes run on 7 October 2026, short hops to long hauls: all answered, no promised field empty
- Charges matched the rows: 1 start, 8 searches, 175 itineraries

What you can do with it:

- Read each leg with its flight number, aircraft type, legroom and operating carrier
- See layover airports, layover length and whether the connection changes airport
- Get the CO2 estimate per itinerary and per leg, with Google's lower-emissions badge
- Compare the current fare with the route's typical and lowest
- Filter on stops, airline, alliance, price, time windows, journey time, layover length, connecting airports and lower emissions
- Search one way or return, in any cabin and currency
- Search several airports at once, or a whole city, and get all the pairings in one run
- Exclude an airline or a whole alliance, and sort by price, time, duration or CO2
- Follow a link straight into Google's booking page for each itinerary
- Ask for the airlines and agencies selling an itinerary, each with its own price
- Hide basic economy fares on the markets that sell them
- See which airline you book and which one actually operates each leg

People use it to track a route daily and catch a fare drop, to build fare alerts, to compare airline pricing on one route across currencies, and to feed a booking or corporate travel tool. It also suits measuring the carbon cost of a travel policy (contrail warming included), researching which aircraft, cabins and legroom serve a route, and keeping a fare history for pricing or academic research.

### What flight data do you get?

| | |
|---|---|
| ✈️ Airline names and codes | Flight number for every leg |
| 💷 Price and currency | One way or return fare |
| 🕑 Departure and arrival times | 📅 Dates, with next-day arrival offset |
| ⏱ Total journey time | Number of stops |
| 🛬 Layover airport, city and length | Airport-change flag on connections |
| Aircraft type per leg | Legroom in inches |
| 🔌 In-seat power and USB | 📶 Free or paid Wi-Fi per leg |
| 🎬 Live TV, on-demand video and streaming | 🧳 Airline baggage policy links |
| 🌱 CO2 per itinerary and per leg | CO2 against the route's typical, lower-emissions badge |
| ☁️ Contrail warming potential | Cabin flown on each leg |
| 💺 Seat type and legroom rating | Codeshare flag per leg |
| Marketing and operating carrier and flight number | 🛫 Origin and destination airport per leg |
| 📈 Daily price history, about two months | Price change since your last run |
| Cheapest, typical and current fare | Alliance and airline filter lists |
| ⭐ Google's best-flights flag | 🔗 Booking link and booking token per itinerary |
| 🏪 Every seller and its price (optional) | 🌐 Seller website and checkout link |

### How to scrape Google Flights

No coding needed: you fill in a form and download a spreadsheet.

1. [Create a free Apify account](https://console.apify.com/sign-up) with your email.
2. Open [Google Flights Scraper](https://apify.com/boncross/google-flights-search).
3. Enter an origin, a destination and a departure date, or paste a Google Flights URL.
4. Add a return date, cabin, passengers and any airline or stop filters you want.
5. Click Start. A single route took 4 to 16 seconds in the measured runs further down.
6. Download the itineraries as Excel or CSV, or as JSON, XML or HTML.

### How much does it cost?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.001 | $0.001 | $0.001 | $0.001 |
| `search-resolved`, per route and date searched, and per itinerary looked up for sellers with `bookingOffers` | $0.0005 | $0.0005 | $0.0005 | $0.0005 |
| `flight-scraped`, per itinerary returned | $0.0002 | $0.00018 | $0.00016 | $0.00014 |

Enterprise plans pay the Business price.

That's **$0.20 per 1,000 flights** on the Free plan and $0.14 on Business. It's the whole price: proxy usage and platform usage are included.

Two worked examples:

- One route returning 100 itineraries: $0.001 + $0.0005 + 100 × $0.0002 = **$0.0215** ($0.0155 on Business).
- Ten routes watched daily for a month, at roughly 100 itineraries each: $0.001 + 10 × $0.0005 + 1,000 × $0.0002 = $0.206 a run, and 30 × $0.206 = **$6.18** ($4.38 on Business).

Apify's Free plan includes $5 of credits a month. That's about 230 searches of 100 itineraries each, or roughly 23,000 flights, before you pay anything.

What you don't pay for:

- A search Google answers with no bookable flights (a route it doesn't sell on that date) isn't charged at all.
- A search that's answered but has nothing left after your filters costs the $0.0005 resolve fee alone.
- Price insights records are never charged.
- An itinerary returned by two searches in one run is returned and charged once.

Seller lookups are the one extra. With the default of 3 itineraries they add 3 × $0.0005 = $0.0015 a route, and the seller records themselves aren't charged per row.

### ⬇️ Input

Give it a route, several routes, or Google Flights URLs. Airport codes such as `LHR` work, and you can also use city codes such as `LON` or `NYC`, which search all of that city's airports.

Got more links than you want to paste? Put them in Start URLs, which loads them in bulk from a file, a Google Sheet or a remote list. The two inputs are combined.

You have two limits. "Max itineraries per search" applies to each target separately: ten targets at 50 each returns 500. "Maximum results for the whole run" caps the run as a whole, and nothing past it is fetched or charged for.

**Several airports at once.** Put more than one code in the origin or the destination, separated by commas, and you get all the pairings in one search: `"origin": "LHR,LGW"` with `"destination": "JFK,EWR"` covers all four. A city code such as `LON`, `NYC` or `TYO` searches that city's airports. Watch out for `LAX`, `BKK` and `SHA`, which are each both an airport code and a city code. List the airports explicitly when you mean the whole area.

**A search returns at most 300 itineraries**, however many airports you list. Widening the origins spends that ceiling on the busiest ones: in testing, two of eight London-area airports contributed nothing. The run warns you when a search hits the cap.

**Passengers and bags.** Besides adults and children you can set "Infants in seat" (their own seat) and "Infants on lap", 0 to 8 each. "Carry-on bags" and "Checked bags" (0 to 5) keep only fares that include that many bags.

**More filters.** "Earliest arrival hour" and "Latest arrival hour" (0 to 23) keep only flights landing within those hours, alongside the departure-hour pair. "Connect only through" keeps itineraries that connect through the airports you list (three letter codes such as `AMS`), and "Connecting airports to avoid" drops the ones that connect through them (such as `ORD` or `CDG`).

**Language.** The language code for airport and airline names. The default is `en`.

**A return trip in economy**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-10",
  "returnDate": "2026-11-17",
  "currency": "GBP"
}
```

**One way, business class, nonstop only**

```json
{
  "origin": "JFK",
  "destination": "LAX",
  "departureDate": "2026-11-20",
  "cabinClass": "business",
  "maxStops": 0,
  "currency": "USD"
}
```

**A morning departure, under ten hours, on one alliance**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-17",
  "returnDate": "2026-11-24",
  "departureTimeFrom": 6,
  "departureTimeTo": 12,
  "maxDurationMinutes": 600,
  "airlines": ["ONEWORLD"]
}
```

**One airline, under a price cap, with a sensible connection**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-17",
  "returnDate": "2026-11-24",
  "airlines": ["BA"],
  "maxPrice": 500,
  "minLayoverMinutes": 90,
  "maxLayoverMinutes": 240
}
```

**Several routes in one run, with a family and a stop limit**

```json
{
  "extraRoutes": [
    "LHR,CDG,2026-11-05",
    "LGW,BCN,2026-11-06,2026-11-10",
    "MAN,DUB,2026-11-07"
  ],
  "adults": 2,
  "children": 1,
  "maxStops": 1,
  "currency": "GBP"
}
```

**Every London airport to every New York airport, cheapest first**

```json
{
  "origin": "LHR,LGW,LCY",
  "destination": "JFK,EWR,LGA",
  "departureDate": "2026-11-17",
  "sortBy": "price",
  "currency": "GBP"
}
```

**Skip an alliance entirely**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-17",
  "excludeAirlines": ["ONEWORLD", "VS"],
  "sortBy": "duration"
}
```

**Lower-emission itineraries only**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-17",
  "lessCo2Only": true,
  "sortBy": "emissions"
}
```

This keeps only the itineraries with Google's green lower-emissions badge (`isLowerEmissions: true`). If you'd like a threshold of your own, each row also has `emissionsKg`, `emissionsTypicalKg` and `emissionsVsTypicalPct` to filter on.

**Who sells the cheapest flight, and for how much**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-17",
  "sortBy": "price",
  "bookingOffers": true,
  "maxOfferItineraries": 3
}
```

**Skip the stripped-down fares**

```json
{
  "origin": "JFK",
  "destination": "LAX",
  "departureDate": "2026-11-17",
  "excludeBasicEconomy": true,
  "currency": "USD"
}
```

Basic economy only exists in some markets, US domestic routes being the main one. Elsewhere the option usually changes nothing. There's no fare-brand column in the rows, and all you'll see is fewer itineraries.

**Watch a route daily and report what moved**

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-10",
  "returnDate": "2026-11-17",
  "trackPriceChanges": true,
  "priceMemoryStore": "new-york-november",
  "includePriceHistory": true
}
```

**Paste a search straight from Google Flights**

```json
{
  "searchUrls": [
    "https://www.google.com/travel/flights/search?tfs=CBwQAhoeEgoyMDI2LTExLTEwagcIARIDTEhScgcIARIDSkZL&hl=en&gl=GB&curr=GBP"
  ]
}
```

#### For developers

- `maxResultsPerSearch` is the per-target limit and `maxItems` the run-wide one. Both default to 0, which means no limit.
- `maxConcurrency` (Parallel requests, default `8`, 1 to 32) sets how many requests run at once across the whole run. Leave it alone unless a run reports errors, then lower it.
- Inside `extraRoutes` a comma already separates the fields, and several airports are joined with `+`: `"LHR+LGW,JFK,2026-11-05"`.
- The passenger and bag keys are `adults`, `children`, `infantsInSeat`, `infantsOnLap`, `carryOnBags` and `checkedBags`. The arrival window is `arrivalTimeFrom` and `arrivalTimeTo`, and the two connecting-airport lists are `onlyConnectingAirports` and `excludeConnectingAirports`.
- `trackPriceChanges` remembers the price of each itinerary in a named storage and fills `previousPrice`, `priceChange`, `priceChangePct` and `previousScrapedAt` on the next run. Give each watchlist its own `priceMemoryStore` name, or they overwrite each other.
- Rows are saved as the run goes. If the platform restarts a run, it carries on where it stopped without saving or charging anything twice.

### ⬆️ Output

You get one record per itinerary (`recordType: "itinerary"`). If you leave price insights on, there's also one price insights record per search, and with `bookingOffers` on, one seller record per seller. The Overview view shows price, airlines, times, duration, stops, CO2 and price change as a table.

```json
{
  "recordType": "itinerary",
  "id": "Scz33c",
  "url": "https://www.google.com/travel/flights/search?tfs=…",
  "scrapedAt": "2026-10-07T19:34:05.491Z",
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-10",
  "returnDate": "2026-11-17",
  "isTopFlight": true,
  "price": 480,
  "isPriceAvailable": true,
  "currency": "GBP",
  "priceType": "round trip",
  "itinerary": null,
  "airlineCode": "BA",
  "airlineNames": ["British Airways"],
  "operatingAirlineNames": ["American", "Iberia", "Finnair"],
  "originCode": "LHR",
  "destinationCode": "JFK",
  "departureAt": "2026-11-10T09:35",
  "departureTime": "09:35",
  "arrivalAt": "2026-11-10T12:35",
  "arrivalDate": "2026-11-10",
  "arrivalTime": "12:35",
  "arrivalDayOffset": 0,
  "durationMinutes": 480,
  "durationText": "8 hr 0 min",
  "stops": 0,
  "layovers": [],
  "emissionsKg": 318,
  "emissionsTypicalKg": 343,
  "emissionsVsTypicalPct": -7,
  "isLowerEmissions": true,
  "legs": [
    {
      "airlineCode": "BA",
      "airlineName": "British Airways",
      "flightNumber": "BA175",
      "originCode": "LHR",
      "originName": "Heathrow Airport",
      "destinationCode": "JFK",
      "destinationName": "John F. Kennedy International Airport",
      "departureAt": "2026-11-10T09:35",
      "departureDate": "2026-11-10",
      "departureTime": "09:35",
      "arrivalAt": "2026-11-10T12:35",
      "arrivalDate": "2026-11-10",
      "arrivalTime": "12:35",
      "arrivalDayOffset": 0,
      "durationMinutes": 480,
      "aircraft": "Boeing 777",
      "legroom": "31 in",
      "legroomText": "31 inches",
      "legroomClass": "average",
      "cabinClass": "economy",
      "operatedByCode": "BA",
      "operatedByName": "British Airways",
      "operatedByFlightNumber": "BA175",
      "marketingCarriers": [
        { "airlineCode": "AA", "airlineName": "American", "flightNumber": "AA6936" },
        { "airlineCode": "IB", "airlineName": "Iberia", "flightNumber": "IB3561" },
        { "airlineCode": "AY", "airlineName": "Finnair", "flightNumber": "AY5475" }
      ],
      "isCodeshare": true,
      "emissionsKg": 318,
      "contrailWarming": "low",
      "amenities": {
        "raw": [null, null, null, null, null, 1, null, null, null, 1, null, 3],
        "powerAndUsbOutlets": false,
        "powerOutlet": false,
        "usbOutlet": true,
        "liveTv": false,
        "onDemandVideo": true,
        "streamToOwnDevice": false,
        "wifiType": "paid",
        "wifi": true,
        "wifiIsPaid": true
      }
    }
  ],
  "baggageUrls": [{ "airlineCode": "BA", "airlineName": "British Airways", "url": "https://www.britishairways.com/en-gb/information/travel-assistance" }],
  "bookingToken": "CjRITTNw…",
  "itineraryToken": "[\"CAISA0dCUBoE…\"]",
  "bookingUrl": "https://www.google.com/travel/flights/booking?tfs=…",
  "previousPrice": 480,
  "priceChange": 0,
  "priceChangePct": 0,
  "previousScrapedAt": "2026-10-07T19:33:04.568Z"
}
```

That fare hadn't moved since the run a minute earlier, which is why its `priceChange` is 0. Here are the same four fields on a fare that did move, a nonstop New York to Los Angeles flight tracked twice 26 minutes apart on 7 October 2026 (the other columns are left out):

```json
{
  "recordType": "itinerary",
  "id": "hlVrjf",
  "origin": "JFK",
  "destination": "LAX",
  "departureDate": "2026-10-08",
  "airlineCode": "DL",
  "price": 389,
  "currency": "GBP",
  "priceType": "one way",
  "scrapedAt": "2026-10-07T23:02:24.091Z",
  "previousPrice": 408,
  "priceChange": -19,
  "priceChangePct": -4.66,
  "previousScrapedAt": "2026-10-07T22:36:39.231Z"
}
```

`previousPrice` is what this itinerary cost on your last tracked run and `previousScrapedAt` is when that was. `priceChange` is the difference in your currency and `priceChangePct` the same in percent, both negative when the fare fell. All four are null on a first run and on an itinerary the store hasn't seen before.

The price insights record has the route's current, lowest and typical fare and a daily price series:

```json
{
  "recordType": "priceInsights",
  "id": "LHR-JFK-2026-11-10-2026-11-17",
  "url": "https://www.google.com/travel/flights/search?tfs=…",
  "scrapedAt": "2026-10-07T19:34:05.507Z",
  "origin": "LHR",
  "destination": "JFK",
  "destinationName": "New York",
  "departureDate": "2026-11-10",
  "returnDate": "2026-11-17",
  "currency": "GBP",
  "currentPrice": 379,
  "lowestRecentPrice": 377,
  "differenceFromLowest": -3,
  "typicalPriceLow": 355,
  "typicalPriceHigh": 440,
  "priceLevelCode": 2,
  "priceHistory": [
    { "date": "2026-08-07", "price": 375 },
    { "date": "2026-08-08", "price": 375 }
  ],
  "filters": {
    "priceRange": { "min": 379, "max": 3062 },
    "alliances": [{ "code": "ONEWORLD", "name": "Oneworld" }],
    "airlines": [{ "code": "BA", "name": "British Airways" }]
  }
}
```

`differenceFromLowest` can be negative. It's how far the current fare sits from Google's reference price, and a negative value means the fare is below it.

With `bookingOffers` on, each seller of a looked-up itinerary is its own record, joined to the itinerary by `itineraryId`:

```json
{
  "recordType": "bookingOffer",
  "itineraryId": "hXefte",
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-17",
  "returnDate": null,
  "sellerCode": "BA",
  "sellerName": "British Airways",
  "isAirlineDirect": true,
  "logoUrl": null,
  "price": 331,
  "currency": "GBP",
  "website": "www.britishairways.com/...",
  "bookingUrl": "https://www.google.com/travel/clk/f?u=…",
  "flights": ["BA175"],
  "scrapedAt": "2026-09-13T19:30:00.000Z"
}
```

A few columns worth knowing before you build on them:

- `price` is for the whole party in your request (all adults, children and infants together), not per person.
- `airlineCode` and `flightNumber` are the flight as Google lists it (`BA175`). On a codeshare, `marketingCarriers` lists the partner airlines that also sell it under their own numbers (`AA6936`, `IB3561`) and `isCodeshare` is true.
- Where another airline flies the aircraft, such as a regional partner, `operatedByName` says so in Google's words ("Republic Airways as American Eagle").
- `bookingUrl` opens Google's page for that exact itinerary, quoted in the currency you searched in.
- `itinerary` is null here. It lists the legs of a multi-city trip, on Google Flights Multi-City.
- `amenities.raw` is Google's own list of flags, kept for reference. Use the named flags beside it.

You can export any of it as JSON, CSV, Excel, XML or HTML from Apify Console, or read it straight from the API.

### How many flights per search, and how fast?

| Search | Itineraries | Time |
|---|---|---|
| London to New York, return | 90 | 5 s |
| London to New York, one way | 121 | 5 s |
| London to New York, nonstop only | 21 | 4 s |
| London to Tokyo, return | 101 | 16 s |
| Three European routes in one run | 152 | 4 s |
| Eight routes in one run, every itinerary | 1,122 | 5 to 7 s |
| Eight routes with price tracking switched on | 1,126 | 3 to 9 s |
| 32 routes in one run, 30 itineraries each | 940 | 6 s |
| 300 routes in one run, 10 itineraries each | 3,000 plus 300 price-insight records | 31 s |

Routes in one run are searched at the same time (8 at once by default), which is why a long list takes little longer than a short one: 32 routes took 18 s one at a time and 6 s at the default. Price tracking adds almost nothing. A bulk run of 300 routes gets through close to 600 searches a minute, and several thousand routes fit comfortably inside the default one-hour run limit. Times are whole runs on Apify, start-up included, measured from 1 to 3 October 2026.

What limits the count is Google. A search returns what Google lists for those dates, usually 90 to 120 itineraries for a single airport pair and occasionally fewer on thin routes. List several airports and that rises toward the ceiling of 300 per search, which is Google's limit and not this actor's. Prices are the fares Google displays for the currency you asked for, and changing the currency changes the answer. A small number of itineraries have no price at all because Google shows none. Those have `isPriceAvailable: false`.

### Limitations

- **Some filters are applied to the rows after Google answers.** Connecting airports, lower emissions, stops, price and duration are each checked on every itinerary before you get it, and the promise holds. But Google filled the page first, and a narrow filter can leave you with fewer rows than the limit you set.
- On very quiet routes Google serves an empty page even though flights exist. Those searches return nothing here. [Google Flights Multi-City](https://apify.com/boncross/google-flights-multi-city) is the actor for those routes.
- Prices are the ones Google shows, not a live airline quote. The booking link opens Google's page for that exact itinerary, but airlines and agencies set their own prices at checkout, and a fare can move between a run and a booking.
- You can't confirm the basic economy option from the output. It shows only as fewer itineraries, and only on markets that sell basic economy.
- Seller lookups have been verified on one way searches. A return trip may give you no seller rows, and the lookups are sometimes unavailable. When that happens you still get the itineraries, the run logs a warning, and no seller rows are returned or charged.
- Excluding an alliance relies on a membership list kept by this actor. An airline that joined very recently may not be excluded.

### FAQ

#### Is scraping Google Flights legal?

Scraping publicly available information is legal in most jurisdictions, and this actor only reads pages anyone can open without signing in. It collects no personal data. How you use the results is your responsibility, and it's worth checking your own obligations before you republish fare data.

#### Do I need proxies or a Google account?

No. Proxy usage is included and there's nothing to set up. You don't need a Google account or an API key either.

#### How do I watch a route and see what moved?

Schedule the run in Apify (daily is typical) and switch on "Compare with the last run". From the second run on, each itinerary shows its previous price and how far it moved, in money and in percent. Watching more than one set of routes? Give each its own "Price memory name" or they'll overwrite each other.

#### Why did my route return nothing, and can I do multi-city trips?

On very quiet routes Google serves no results for an ordinary search even though flights exist, and trips of three legs or more are served differently. [Google Flights Multi-City](https://apify.com/boncross/google-flights-multi-city) is built for both.

#### Is the price per person?

It's for the whole party. Search with two adults and a child and `price` is the fare for all three together.

#### Which filters and sorts are there?

Stops (0 for nonstop only, or at most one, two or three), one airline or alliance to keep, airlines or a whole alliance to drop (`ONEWORLD`, `STAR_ALLIANCE`, `SKYTEAM`), a maximum price, a maximum journey time, departure and arrival hour windows, minimum and maximum layover, connecting airports to use or to avoid, Google's lower-emission itineraries only, bag counts, and hiding basic economy. You can sort by price, journey time, departure time, arrival time, CO2 or number of stops, and `top` keeps Google's ranking. Sorting is applied to the complete list, not to a first page.

#### Can I see who sells a flight, not just the price?

Switch on "Also return every seller and its price". The first few itineraries then get a record per seller, the airlines direct and the agencies beside them, each with its own price and a link into its checkout. "How many itineraries to price" sets how many are looked up, and each one is charged as one `search-resolved`. If sellers are all you want, [Google Flights Booking Options](https://apify.com/boncross/google-flights-booking-options) does that job alone.

#### Which airline do the results name on a codeshare?

The airline Google lists the flight under, in `airlineCode` and `flightNumber`. The partners that sell the same seat under their own numbers are in `marketingCarriers`, with `isCodeshare` true, and `operatedByName` names the airline flying the aircraft where that's a different one.

#### Why are some prices missing?

Google occasionally lists an itinerary with no fare attached. You'll see `isPriceAvailable: false` and a null price on those, which is safer than a misleading zero.

### API, integrations and AI agents

A fare watch needs no code: Apify's scheduler runs the actor daily, and a webhook or the Slack and Google Sheets integrations can pass on what moved. Zapier, Make, Airbyte and GitHub connect the same way.

From your own code, one call to the Apify API runs the actor and returns the dataset. There are clients for JavaScript and Python.

```
POST https://api.apify.com/v2/acts/boncross~google-flights-search/run-sync-get-dataset-items?token=YOUR_TOKEN
```

For AI agents, point your MCP client at the Apify MCP server (`mcp.apify.com`) and reference the actor as `boncross/google-flights-search`. Your agent sends the input JSON and gets the dataset back.

### More from BonCross

- [Google Flights Booking Options Scraper](https://apify.com/boncross/google-flights-booking-options): See every airline and travel agency selling the same flight, each with its own price…
- [Google Flights Multi-City Scraper](https://apify.com/boncross/google-flights-multi-city): Google Flights multi-city trips of three legs or more, and quiet routes Google leaves…
- [Google Maps Directions Scraper](https://apify.com/boncross/google-maps-directions): Google Maps directions as JSON for driving, transit, walking and cycling.
- [Google Hotels Search Scraper](https://apify.com/boncross/google-hotels-search): Google Hotels prices for a whole city or map area.
- [Accor Hotel Details Scraper](https://apify.com/boncross/accor-hotel-details): Full Accor hotel records.
- [Agoda Search Scraper](https://apify.com/boncross/agoda-search): Agoda search results for any destination and dates.

### Your feedback

Found a wrong fare, a missing field or a route that should work? Post the route and date on this actor's Issues tab in Apify Console. We read every issue and reply there, and feature requests shape what BonCross adds next.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/google-flights-search/changelog.md

# Actor input Schema

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

Departure airport code such as LHR. A city code such as LON or NYC searches every airport in that city. Several can be given, separated by commas, to search them together: "LHR,LGW,LCY". Note LAX, BKK and SHA are both an airport and a city code, so list the airports explicitly if you mean the whole area. You can also type a place name such as "Barcelona" or "Heathrow" and it is resolved for you.

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

Arrival airport code such as JFK. A city code such as NYC searches every airport in that city. Several can be given, separated by commas: "JFK,EWR,LGA". You can also type a place name such as "Barcelona" or "Heathrow" and it is resolved for you.

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

Outbound date as YYYY-MM-DD.

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

Return date as YYYY-MM-DD. Leave empty for a one way search.

## `extraRoutes` (type: `array`):

One route per line as origin, destination, departure date and an optional return date. Commas separate the fields, so a multi-airport origin uses + instead: "LHR+LGW,JFK+EWR,2026-11-05,2026-11-12".

## `searchUrls` (type: `array`):

Paste search URLs straight from Google Flights. The route, dates, cabin and filters already in the URL are used as they are.

## `startUrls` (type: `array`):

Google Flights page addresses, with the option to load them in bulk from a file, a Google Sheet or a remote list. Use this when you have more links than you want to paste. Combined with anything in the list above.

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

Stop after this many itineraries for each route. 0 returns every itinerary Google lists.

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

A run-wide ceiling across every route. Zero means no run-wide limit. Rows that report an input the actor could not resolve are not counted here and are never charged for.

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

Travel class the fares are quoted in.

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

Number of adult passengers.

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

Number of children aged 2 to 11.

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

Number of infants travelling in their own seat.

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

Number of infants travelling on an adult lap.

## `carryOnBags` (type: `integer`):

Keep only fares that include this many carry-on bags.

## `checkedBags` (type: `integer`):

Keep only fares that include this many checked bags.

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

Leave empty for any number of stops. 0 keeps nonstop flights only, 1 keeps one stop or fewer, 2 keeps two or fewer.

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

Keep only these carriers. Two letter airline codes such as BA or AA, or an alliance: ONEWORLD, SKYTEAM, STAR_ALLIANCE.

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

Keep only itineraries at or below this fare, in the currency you asked for.

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

Keep only flights leaving at or after this hour, 0 to 23.

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

Keep only flights leaving at or before this hour, 0 to 23.

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

Keep only flights landing at or after this hour, 0 to 23.

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

Keep only flights landing at or before this hour, 0 to 23.

## `maxDurationMinutes` (type: `integer`):

Keep only itineraries no longer than this many minutes door to door.

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

Drop itineraries with a connection shorter than this many minutes.

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

Drop itineraries with a connection longer than this many minutes.

## `onlyConnectingAirports` (type: `array`):

Keep only itineraries that connect through these airports. Three letter codes such as BOS or AMS.

## `excludeConnectingAirports` (type: `array`):

Drop itineraries that connect through these airports. Three letter codes such as ORD or CDG.

## `lessCo2Only` (type: `boolean`):

Keep only the itineraries Google marks with its green lower-emissions badge (well below typical CO2 for the route). Every row also carries emissionsKg, emissionsTypicalKg and emissionsVsTypicalPct if you want a threshold of your own.

## `includePriceHistory` (type: `boolean`):

Add one record per search with the current, lowest and typical price plus a day by day price history for the route.

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

Three letter currency code the prices come back in. Default USD.

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

Language code for airport and airline names.

## `trackPriceChanges` (type: `boolean`):

Remember each itinerary's price between runs and report what changed. Fills previousPrice, priceChange, priceChangePct and previousScrapedAt.

## `priceMemoryStore` (type: `string`):

Named storage the remembered prices live in. Use different names to keep separate watchlists apart.

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

Airline codes to leave out, such as "AA". An alliance name (ONEWORLD, STAR_ALLIANCE, SKYTEAM) excludes its members. An itinerary is dropped if any of its flights match. Alliance membership is maintained here rather than published by the site, so a very recently joined member may not be recognised.

## `sortBy` (type: `string`):

Order of the returned rows. "top" keeps the ranking the site itself uses.

## `bookingOffers` (type: `boolean`):

Adds a row per seller for the first few itineraries, with price, website and booking link. One extra resolved search is charged per itinerary looked up.

## `maxOfferItineraries` (type: `integer`):

Sellers are fetched one itinerary at a time, so this caps the cost. Sorting by price first puts the cheapest itineraries at the front of the queue.

## `excludeBasicEconomy` (type: `boolean`):

Leave out the strippedown fares that do not include a seat choice or a carry-on. Only markets that sell them are affected: a US domestic search drops around an eighth of its results, a transatlantic one usually none.

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

How many requests run at once across the whole run. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

## `restartAttempt` (type: `integer`):

Set by the actor when it restarts itself in a fresh container after being refused. Leave it alone.

## Actor input object example

```json
{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-10",
  "returnDate": "",
  "extraRoutes": [],
  "searchUrls": [],
  "startUrls": [],
  "maxResultsPerSearch": 0,
  "maxItems": 0,
  "cabinClass": "economy",
  "adults": 1,
  "children": 0,
  "infantsInSeat": 0,
  "infantsOnLap": 0,
  "carryOnBags": 0,
  "checkedBags": 0,
  "airlines": [],
  "onlyConnectingAirports": [],
  "excludeConnectingAirports": [],
  "lessCo2Only": false,
  "includePriceHistory": true,
  "currency": "USD",
  "language": "en",
  "trackPriceChanges": false,
  "priceMemoryStore": "google-flights-prices",
  "excludeAirlines": [],
  "sortBy": "top",
  "bookingOffers": false,
  "maxOfferItineraries": 3,
  "excludeBasicEconomy": false,
  "maxConcurrency": 8,
  "restartAttempt": 0
}
```

# Actor output Schema

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

Google Flights results: every row the run returned.

## `stats` (type: `string`):

Counts for the run: what was resolved, fetched, filtered and returned.

# 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 = {
    "origin": "LHR",
    "destination": "JFK",
    "departureDate": "2026-11-10",
    "excludeAirlines": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/google-flights-search").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 = {
    "origin": "LHR",
    "destination": "JFK",
    "departureDate": "2026-11-10",
    "excludeAirlines": [],
}

# Run the Actor and wait for it to finish
run = client.actor("boncross/google-flights-search").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 '{
  "origin": "LHR",
  "destination": "JFK",
  "departureDate": "2026-11-10",
  "excludeAirlines": []
}' |
apify call boncross/google-flights-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,boncross/google-flights-search"
        }
    }
}
```

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/rAamQf71kn8hRIpYt/builds/AJlFVFJ1oDQxZeBRn/openapi.json
