# Google Flights Scraper — Fares, Flight Numbers, Layovers, CO2 (`scrapersdelight/google-flights-scraper`) Actor

Search Google Flights by route and date and get every itinerary on the board: price, airline, per-leg flight numbers, layovers, stops, duration, baggage and CO2. One-way and round-trip. Pay only for itineraries returned — $0.30 per 1,000.

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

## Pricing

$0.30 / 1,000 per flight itineraries

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## ✈️ Google Flights Scraper — fares, per-leg flight numbers, layovers and CO2

Give it a route and a date. Get back **every itinerary Google Flights puts on that fare board** — the
price, the airline, **the actual flight number of every leg**, each layover with its airport and
duration, stops, total duration, baggage allowance and the full CO2 block.

No API key. No login. No browser. One HTTP request per board, parsed out of Google's own
server-rendered HTML.

**$0.30 per 1,000 itineraries. You pay per itinerary returned — nothing else.**

***

### 🎯 The two things this does that the lane does not

#### 1. Per-leg flight numbers, without a second request

Most Google Flights scrapers hand you `"1 stop, Alaska, 10 hr 12 min"` and stop there. This one gives
you the itinerary Google itself files with the Travel Impact Model:

```json
"legs": [
  { "origin": "JFK", "destination": "SEA", "carrierCode": "AS", "flightNumber": "21",  "date": "2026-10-15" },
  { "origin": "SEA", "destination": "LAX", "carrierCode": "AS", "flightNumber": "487", "date": "2026-10-15" }
],
"flightNumbers": ["AS21", "AS487"],
"layovers": [
  { "ordinal": "1 of 1", "airportCode": "SEA", "airportName": "Seattle-Tacoma International Airport",
    "city": "Seattle", "durationText": "58 min", "durationMinutes": 58 }
]
```

That is a real row from a real board. Flight numbers make a fare row **joinable** — to schedules, to
OAG/Cirium data, to your own inventory — instead of just readable.

#### 2. You are not billed twice for the same flight

**Google renders every fare board twice.** A JFK→LAX board contains **196** itinerary `<li>` elements
for **98** real itineraries — same `ssk`, same `data-id`, same aria-label, same layovers, rendered
into two sets of containers. Measured on four boards: 196→98, 178→89, 114→57, 96→48.

The obvious parser (`cheerio → li.pIav2d → push`) emits all 196 and bills you for all 196. This actor
deduplicates **before** anything is delivered or charged. On the validation run below: **400 raw rows
read, 75 delivered, 75 billed.**

***

### 📦 What you get on every row — 65 fields

#### Search context

`itineraryId` · `section` (Google's own "Top flights" vs "Other flights" bucket) · `rankInSection` ·
`searchOrigin` · `searchDestination` · `searchDepartureDate` · `searchReturnDate` · `tripType` ·
`cabinClass` · `passengers` · `currency` · `currencyName` · `searchUrl` · `tfsToken` · `scrapedAt`

#### Price

`price` (numeric) · `priceFormatted` (`"$204"`, `"£1,455"`) · `priceType` (`one way` /
`round trip total`) · `priceUnavailable` · `bookingToken` · `priceLevel` (`low`/`typical`/`high`
from Google's Price-insights panel) · `priceDeltaVsUsual` (signed, e.g. `-46`) · `bookingTip` ·
`resultsOnBoard`

#### Airlines

`airlines[]` · `airlineCodes[]` (IATA, derived per leg — works on multi-carrier rows where the logo
is absent) · `airlineLogoUrl` · `operatedBy` (`"Operated by Republic Airways as American Eagle"`) ·
`isCodeshare` · `mixedCabin` (`"Business Class + Premium Economy"`)

#### Schedule

`departureTime` · `departureDate` · `departureDateTimeIso` · `arrivalTime` · `arrivalDate` ·
`arrivalDateTimeIso` · `arrivalDayOffset` (`+1` / `+2`) · `durationText` · `durationMinutes` ·
`originCode` · `originName` · `destinationCode` · `destinationName`

#### Routing

`stops` · `stopsText` · `layovers[]` (`ordinal`, `airportCode`, `airportName`, `city`,
`durationText`, `durationMinutes`, `transferFrom`, `transferTo`) · `longLayover` ·
`changeOfAirport` · `legs[]` · `flightNumbers[]`

#### Baggage

`carryOnBagsIncluded` · `checkedBagsIncluded` · `baggageNote`

#### Emissions (the full block Google exposes)

`co2Grams` · `co2Kg` · `co2TypicalGrams` · `co2SavingsGrams` · `co2PercentVsTypical` ·
`emissionsLabel` · `relativeEmissions` (1 = low, 3 = high) · `environmentalRanking` ·
`contrailsImpact` · `easaSafDiscountGrams` · `travelImpactModelUrl` · `seatingClassCode`

***

### 📊 Measured field fill — from a real Apify run, not an estimate

**Run `t17MbzlTYmjUVhwdm`, 2026-09-03. 3 boards, 75 itineraries delivered, SUCCEEDED in 11.4 s,
peak memory 415 MB, `chargedEventCounts` = 75.**
Searches: JFK→LAX 2026-10-15 one-way (**97** on the board), JFK→BKK 2026-11-10 one-way (**58**),
JFK↔LAX 2026-11-10/17 round-trip (**45**), each capped at 25 rows.

**65 fields on every row. 56 of them at 100% fill.**

| Field group | Fill |
|---|---|
| ids, search context, `currency`, `currencyName`, `searchUrl`, `tfsToken`, `scrapedAt` | **100%** |
| `price`, `priceFormatted`, `priceType`, `priceUnavailable`, `bookingToken` | **100%** |
| `airlines`, `airlineCodes`, `airlineLogoUrl`, `isCodeshare` | **100%** |
| all 8 schedule fields + `arrivalDayOffset`, `durationText`, `durationMinutes` | **100%** |
| `originCode/Name`, `destinationCode/Name`, `stops`, `stopsText` | **100%** |
| `legs`, `flightNumbers`, `longLayover`, `changeOfAirport` | **100%** |
| all 12 emissions fields incl. `travelImpactModelUrl` | **100%** |
| `priceLevel`, `resultsOnBoard` | **100%** |
| `layovers` | **56.0%** — nonstop rows have none, by definition |
| `carryOnBagsIncluded`, `checkedBagsIncluded`, `baggageNote` | **66.7%** — Google omits the baggage line on some international fares |
| `searchReturnDate`, `priceDeltaVsUsual`, `bookingTip` | **33.3%** — only on the round-trip search / only when Google shows that panel |
| `operatedBy` | **1.3%** — a codeshare marker; it is true data, not a gap |
| `mixedCabin` | **0%** on this run — economy boards don't mix cabins (measured 12 of 89 rows on a business board) |

Nothing above is padding: `layovers` is empty on nonstop rows because a nonstop flight has no
layover, and `operatedBy` is rare because codeshares are rare (12 of 98, 15 of 89, 2 of 48 and 1 of
57 rows on the four validation boards).

#### Also validated offline against 7 captured boards — exact row counts

| Board | Raw `<li>` | Unique itineraries | Parsed |
|---|---|---|---|
| JFK→LAX one-way (residential proxy) | 196 | **98** | 98 ✅ |
| JFK→LAX one-way (datacenter proxy) | 196 | **98** | 98 ✅ |
| JFK→LAX one-way (direct) | 196 | **98** | 98 ✅ |
| JFK↔LAX round-trip | 96 | **48** | 48 ✅ |
| JFK→BKK one-way | 114 | **57** | 57 ✅ |
| JFK→LHR business, GBP, 2 pax | 178 | **89** | 89 ✅ |
| LWS→BFF (no such route) | 0 | **0** | 0 ✅ clean empty |

488 rows, every `itineraryId` unique, `£1,455` parsed as `price: 1455` + `currencyName: "British pounds"`.

***

### 🚀 How to use it

#### Simplest — one route

```json
{ "origin": "JFK", "destination": "LAX", "departureDate": "2026-10-15" }
```

#### Evergreen (for a schedule — never goes stale)

```json
{ "origin": "JFK", "destination": "LAX", "daysFromNow": 30, "maxResultsPerSearch": 25 }
```

Leave `departureDate` blank and the actor computes the date at run time, so a saved task or a nightly
schedule never starts searching a date in the past.

#### Round trip

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

#### Many routes and dates in one run

```json
{
  "searches": [
    { "origin": "JFK", "destination": "LAX", "departureDate": "2026-10-15" },
    { "origin": "JFK", "destination": "LHR", "departureDate": "2026-10-16", "returnDate": "2026-10-23" },
    { "origin": "SFO", "destination": "NRT", "departureDate": "2026-10-20" }
  ],
  "cabinClass": "business",
  "currency": "USD"
}
```

#### Every input

| Input | Default | What it does |
|---|---|---|
| `origin` / `destination` | `JFK` / `LAX` | IATA airport or city codes |
| `departureDate` | — | `YYYY-MM-DD`; blank uses `daysFromNow` |
| `returnDate` | — | set it and the search becomes a round trip |
| `daysFromNow` | `30` | used when `departureDate` is blank |
| `tripType` | `one-way` | `one-way` or `round-trip` |
| `searches` | `[]` | bulk list; each entry overrides the single-route fields |
| `adults` / `children` / `infantsInSeat` / `infantsOnLap` | `1` / `0` / `0` / `0` | passenger mix |
| `cabinClass` | `economy` | `economy`, `premium-economy`, `business`, `first` |
| `maxStops` | `any` | `0` nonstop only, `1`, `2` — applied by Google, so the response is smaller and faster |
| `currency` / `country` / `language` | `USD` / `US` / `en` | point of sale; fares genuinely differ by it |
| `maxResultsPerSearch` | `0` (whole board) | cap applied **before** delivery, so you are never billed past it |
| `skipPriceUnavailable` | `false` | drop rows Google has no sellable price for |
| `proxyConfiguration` | Apify Proxy, automatic pool | switch to `RESIDENTIAL` or bring your own |

***

### 💵 Pricing

**Pay per event: `flight-scraped` — $0.0003 per itinerary ($0.30 per 1,000).** No start fee, no
per-run fee, no per-page fee, no usage surcharge. A duplicate render is never billed; a row dropped
by `maxResultsPerSearch` or `skipPriceUnavailable` is never billed.

| Board (measured) | Itineraries | You pay |
|---|---|---|
| JFK→LAX one-way | 98 | **$0.029** |
| JFK→LHR business, 2 pax | 89 | **$0.027** |
| JFK→BKK one-way | 57 | **$0.017** |
| JFK↔LAX round-trip | 48 | **$0.014** |
| 30 routes × 60 departure dates ≈ 126,000 rows | | **≈ $38** |

Rows with `priceUnavailable: true` (2–8% of a board in testing) are real itineraries with full
schedule, per-leg and CO2 data, and they **are** billed. Set `skipPriceUnavailable: true` if you do
not want them.

***

### ⚠️ Honest limits — what this does NOT do

- **No multi-city.** Not a shortcut — a measured wall. Google accepts a multi-city request and
  renders the search form with every leg filled in correctly, then ships **zero** server-rendered
  result rows: HTTP 200, ~1.89 MB, **0 itinerary elements**, across trip-type values 3, 4 and 5 and
  five `tfu` parameter variants. Those boards are built client-side, so no HTTP-only scraper can read
  them. One-way and round-trip are fully supported.
- **A round-trip board is the DEPARTING slice.** This is how Google works, not a shortcut here.
  Every row on a round-trip board is an outbound itinerary priced as the **round-trip total** —
  measured 48 of 48 rows carrying `"From 357 US dollars round trip total"`. The return leg is a
  second selection Google does not put on this board. Rows say so explicitly:
  `priceType: "round trip total"`, and `legs[]` covers the outbound slice only.
- **No booking-option / OTA list.** The per-itinerary list of who sells the fare and at what price is
  behind a click; this actor reads the board.
- **No price calendar / date grid and no Explore.** Different pages, deliberately out of scope.
- **`departureDateTimeIso` and `arrivalDateTimeIso` carry no timezone.** They are local airport clock
  times, exactly as Google shows them. `arrivalDayOffset` gives you the `+1` / `+2` day roll.
- **Prices are what Google displays**, not a booked fare. They move, and they differ by `country`
  and `currency`.
- **English only.** The parser reads Google's English accessibility sentences. Leave `language: en`;
  `currency` and `country` still control pricing and point of sale.

#### Anti-bot and proxy — measured, not guessed

Verified on 2026-09-02 by running the same JFK→LAX board three ways:

| Route | Status | Bytes | Itineraries | Time |
|---|---|---|---|---|
| Direct (no proxy) | 200 | 7,638,349 | 98 | — |
| Apify Proxy `RESIDENTIAL` + `country-US` | 200 | 7,644,199 | 98 | 6,482 ms |
| Apify Proxy automatic (datacenter) | 200 | 7,644,082 | 98 | 3,431 ms |

No CAPTCHA, no challenge, no JS execution needed. **The datacenter pool is the default** because it
returned identical data about twice as fast and at effectively no proxy cost; residential runs about
$0.0026 per search at the measured 329 KB of compressed traffic. One residential request during
testing returned an Apify-proxy `590 UPSTREAM504` with 0 bytes while others succeeded — transient, so
the actor retries up to 4 times with a fresh session each time.

**A blocked run never reports "no flights found."** If no board can be read, the run exits cleanly
with a status message that names it as a transport failure. A genuinely empty board is a different,
distinguishable case (LWS→BFF returned 200 / 1.79 MB / 0 rows) and is reported as such.

#### robots.txt

`https://www.google.com/robots.txt` line 176, under `User-agent: *`, reads verbatim:

```
Disallow: /travel/flights/search
```

That is the path this actor reads. It is disclosed here so you can make your own call. Use the output
in line with Google's terms and the law in your jurisdiction; you are responsible for how you use it.

***

### 🛠 How it works

One `GET https://www.google.com/travel/flights/search?tfs=…&hl=…&gl=…&curr=…&tfu=EgYIABABGAA` per
board. `tfs` is a base64url protobuf encoding the route, dates, passenger mix, cabin and stop cap —
hand-built by this actor, with a self-check that asserts the encoder still reproduces a known-good
token before any request goes out (a wrong token would return a perfectly valid page for the *wrong*
route).

`tfu=EgYIABABGAA` is not optional: with it a JFK→LAX board carries 97–98 itineraries for 328,862
compressed bytes; without it, 32 itineraries for 270,067 bytes.

Parsing is anchored on the **stable semantic layer** — Google's accessibility sentences and the
`data-*` attributes of the Travel Impact Model block, which is a public contract — rather than on
obfuscated class names, which Google rotates without notice. Class selectors are used only as the
fast path, always with an aria/attribute fallback, and the run fails loudly rather than silently if
itinerary elements are present but none parse.

***

### ❓ FAQ

**Do I need a Google API key?** No. No key, no login, no cookies.

**How many itineraries come back per search?** The whole board. Measured: 98 (JFK→LAX one-way),
89 (JFK→LHR business), 58 (JFK→BKK), 45–48 (JFK↔LAX round-trip). `resultsOnBoard` on every row tells
you the true board size even when you cap the rows you keep.

**Why is the price on the row different from the visible text on Google's page?** It isn't — the
visible price text is font-obfuscated, so the number is read from Google's own accessibility label
(`"214 US dollars"`), which is why `currencyName` comes back too.

**Can I get the return flights of a round trip?** Not from this board — see honest limits. You get
the departing itineraries priced as the round-trip total.

**Can I search many dates?** Yes — put one entry per date in `searches`. That is the normal way to
build a fare-history or fare-alert dataset.

**Is `priceUnavailable` a bug?** No. Google lists some itineraries with no sellable price. They keep
full schedule, per-leg and CO2 data. Set `skipPriceUnavailable: true` to drop them.

**How fast is it?** 3–7 seconds per board including the fetch. The 3-board validation run finished
in 11.4 seconds.

**What happens on an impossible route?** A clean run with zero rows and a status message saying so —
never a failure, and never confused with a block.

# Actor input Schema

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

Three-letter IATA code the flight departs from, e.g. `JFK`, `LHR`, `SIN`. City codes work too (`NYC`, `LON`).

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

Three-letter IATA code the flight arrives at, e.g. `LAX`, `BKK`, `CDG`.

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

The outbound date. Leave empty and the actor uses **Days from now** instead, so a saved task or schedule never goes stale on a hard-coded past date.

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

Only for a round-trip search. Setting it switches the trip type to round-trip automatically. Note: a Google round-trip board lists the DEPARTING flights priced as a round-trip total — the return leg is a second selection Google does not put on this board.

## `daysFromNow` (type: `integer`):

How far ahead to search when **Departure date** is blank. Keeps scheduled runs evergreen.

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

`one-way`, or `round-trip` (which needs a return date; if you omit one the actor searches a 7-day trip). Multi-city is not offered — Google does not server-render those boards, so no scraper can read them from this data path without a browser.

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

Optional. Run many routes/dates in one go — each entry overrides the single-route fields above. Example: `[{"origin":"JFK","destination":"LAX","departureDate":"2026-10-15"},{"origin":"JFK","destination":"LHR","departureDate":"2026-10-16","returnDate":"2026-10-23"}]`. Passenger mix, cabin, currency and stop cap apply to every entry.

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

Adult passengers (12+). Fares are shown per passenger; the round-trip total is for the whole party.

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

Children aged 2-11.

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

Infants under 2 travelling in their own seat.

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

Infants under 2 travelling on an adult's lap.

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

Google searches this cabin or better. Business and first boards are smaller and carry more `Price unavailable` rows (measured 7 of 89 on a JFK-LHR business board) — those rows still have full schedule, leg and CO2 data.

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

Filter applied by Google before it builds the board, so it also makes the response much smaller and faster. Measured on JFK-LAX: `0` returned 62 nonstop rows only; `1` added 130 one-stop rows.

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

ISO currency code Google should price in, e.g. `USD`, `GBP`, `EUR`, `AUD`. Each row also carries `currencyName` read straight from the page ("US dollars", "British pounds").

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

Two-letter country Google prices and localises for, e.g. `US`, `GB`, `DE`. Fares genuinely differ by point of sale.

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

Interface language. Leave at `en` — the parser reads Google's English accessibility sentences, and another language changes those strings.

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

Caps how many itineraries are saved (and billed) from each board. `0` = the whole board. Measured board sizes: 98 (JFK-LAX one-way), 89 (JFK-LHR business), 57 (JFK-BKK), 48 (JFK-LAX round-trip). The cap is applied BEFORE delivery, so you are never charged for rows you did not ask for.

## `skipPriceUnavailable` (type: `boolean`):

Google lists some itineraries with no sellable price (2-8% of rows in testing). They still carry full schedule, per-leg flight numbers, layovers and CO2. Switch this on to drop them so you neither receive nor pay for them.

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

Defaults to Apify Proxy on the automatic (datacenter) pool — measured 200 with identical row counts to residential and about twice as fast (3.4 s vs 6.5 s per board). Escalate to `RESIDENTIAL` only if you see repeated failures; at ~329 KB per search residential costs roughly $0.0026 a search. You can also plug in your own proxies here.

## Actor input object example

```json
{
  "origin": "JFK",
  "destination": "LAX",
  "departureDate": "2026-10-15",
  "returnDate": "2026-10-22",
  "daysFromNow": 30,
  "tripType": "one-way",
  "searches": [],
  "adults": 1,
  "children": 0,
  "infantsInSeat": 0,
  "infantsOnLap": 0,
  "cabinClass": "economy",
  "maxStops": "any",
  "currency": "USD",
  "country": "US",
  "language": "en",
  "maxResultsPerSearch": 25,
  "skipPriceUnavailable": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `itineraries` (type: `string`):

The dataset of scraped Google Flights itineraries (one item per unique itinerary, deduped before billing).

# 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": "JFK",
    "destination": "LAX",
    "daysFromNow": 30,
    "maxResultsPerSearch": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/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 = {
    "origin": "JFK",
    "destination": "LAX",
    "daysFromNow": 30,
    "maxResultsPerSearch": 25,
}

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

```

## MCP server setup

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