# Skyscanner Flight Scraper — Price Calendar, Fares & Itineraries (`brilliant_gum/skyscanner-scraper`) Actor

No-login Skyscanner scraper: cheapest-by-date price calendar, cheapest fares by date, and airport/city search. Plus full live itineraries (times, segments, layovers, both round-trip legs, baggage, multi-source prices, booking links) from Google Flights + Kiwi.com. No API key.

- **URL**: https://apify.com/brilliant\_gum/skyscanner-scraper.md
- **Developed by:** [Yuliia Kulakova](https://apify.com/brilliant_gum) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.003 / calendar day

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Skyscanner Flight Scraper — Price Calendar, Fares & Itineraries

![Skyscanner Flight Scraper](https://api.apify.com/v2/key-value-stores/IuFu0Cw6PpOkNkDV7/records/skyscanner-banner)

No-login flight scraper. Its core is Skyscanner's signature **cheapest-by-date price calendar** — one
record per day across up to 12 months with the cheapest **direct** and **indirect** price, carrier and
operating airport — plus **cheapest fares by date** and **airport/city search**. On top of that it returns
**full live itineraries** (exact times, per-segment flight numbers, layovers, both round-trip legs, baggage,
multi-source prices and booking links) sourced from **Google Flights**, with **Kiwi.com** as a second price
source. No login, no API key.

### Modes (combinable — set `mode`)

| Mode | What it returns |
|---|---|
| **calendar** (`cheapest-by-date`) — *default* | The whole **price calendar**: one record per day across up to 12 months (`monthsAhead`). Cheapest **direct** & **indirect** price per day, cheapest carrier, operating airport, direct-available flag, relative price tier, deep link. |
| **search** | The cheapest fare for a route on a specific date (one-way) or depart+return pair (round-trip). One record per date with the cheapest **direct** and **indirect** fare — price, airline, operating airport, agent, deep link. Supports a date range (`departDate`…`departDateEnd`). |
| **places** (`autosuggest`) | Resolve an airport/city query or IATA code to place entities: PlaceId, IATA, city, region, country, GeoId, latitude/longitude. |
| **itineraries** (`itinerary`, `flights`, `live`) | The **full live flight list** (sourced from Google Flights, cross-priced with Kiwi.com): per itinerary — `departureTime`/`arrivalTime` (local ISO), `durationMinutes`, `stopCount`, `legs[]` (flightNumber, airline, aircraft, per-leg times), `layovers[]`, `price`+`currency`, `baggage` (when matched via Kiwi), `tags` (cheapest/fastest/best), `score`, carbon, a multi-source `priceSources[]` table with `bestPrice`/`cheapestSource`/`sourcesFound`. Supports one-way, round-trip (both legs when available) and multi-city. |

### Quick start

Cheapest-by-date calendar (default):

```json
{ "mode": ["calendar"], "origin": "JFK", "destination": "LAX", "monthsAhead": 6 }
```

Cheapest fare(s) by date:

```json
{ "mode": ["search"], "origin": "JFK", "destination": "LAX", "departDate": "2026-10-15", "departDateEnd": "2026-10-20" }
```

Full itineraries (one-way; add `"returnDate"` for round-trip):

```json
{ "mode": ["itineraries"], "origin": "JFK", "destination": "LAX", "departDate": "2026-10-15", "adults": 1 }
```

Multi-city itineraries: pass `multiCityLegs` (`[{origin,destination,date}, …]`). Places:
`{ "mode": ["places"], "placeQueries": ["Heathrow", "Tokyo"] }`.

> Dates are auto-corrected: a past or empty `departDate` is shifted forward automatically, so scheduled runs never query a stale date.

### Example — calendar day (real, trimmed — JFK→LAX)

```json
{
  "recordType": "calendarDay", "tripType": "one-way", "origin": "JFK", "destination": "LAX",
  "departDate": "2026-10-03", "price": 229, "priceType": "direct", "priceTier": "low",
  "isDirect": true, "cheapestCarrierName": "JetBlue",
  "direct":   { "available": true, "price": 229, "carrierName": "JetBlue", "operatingOrigin": "JFK", "stops": 0 },
  "indirect": { "available": true, "price": 285, "carrierName": "Alaska Airlines", "operatingOrigin": "JFK", "minStops": 1 },
  "deepLink": "https://www.skyscanner.net/transport/flights/jfk/lax/261003/"
}
```

`operatingOrigin`/`operatingDestination` are disclosed because Skyscanner's month grid can aggregate a whole
city (a `JFK` request may surface an `EWR`/`LGA` quote); `requestedOriginMatch`/`requestedDestinationMatch`
flag mismatches, and `strictAirport: true` drops non-matching airports. `indirect.minStops` is a floor (1) —
an indirect fare can involve more than one stop.

### Example — itinerary (real, trimmed — JFK→LAX one-way)

```json
{
  "recordType": "itinerary", "source": "google_flights", "tripType": "one-way",
  "origin": "JFK", "destination": "LAX", "price": 219, "currency": "USD",
  "departureTime": "2026-10-15T15:43:00", "arrivalTime": "2026-10-15T18:53:00",
  "durationMinutes": 370, "stopCount": 0, "isDirect": true,
  "legs": [ { "flightNumber": "B61523", "airlineCode": "B6", "airlineName": "JetBlue",
              "aircraft": "Airbus A320", "from": "JFK", "to": "LAX",
              "departureTime": "2026-10-15T15:43:00", "arrivalTime": "2026-10-15T18:53:00", "durationMinutes": 370 } ],
  "tags": ["best"], "score": 96,
  "baggage": { "carryOn": 1, "checked": 0, "personal": 1 },
  "priceSources": [ { "source": "google_flights", "price": 219, "currency": "USD" },
                    { "source": "kiwi", "price": 230, "currency": "USD" } ],
  "bestPrice": 219, "cheapestSource": "google_flights", "sourcesFound": 2,
  "bookingLink": "https://www.google.com/travel/flights/search?tfs=..."
}
```

- `departureTime`/`arrivalTime` are **airport-local** wall-clock (`YYYY-MM-DDTHH:MM:00`), each leg with its own times.
- **Round-trip** returns both legs (`outbound`+`return`+round-trip total) for the top `roundTripReturnDetail`
  outbound options; `hasReturnDetail` flags whether return-leg segments were resolved (set
  `roundTripReturnDetail: 0` for the fast, outbound-only mode).
- **Multi-city** returns full itineraries for every leg, grouped by `multiCityId`; each leg is priced one-way
  (the true combined multi-city fare may differ).
- **Multi-source & baggage** — with `compareSources: true` (default) each itinerary is matched to Kiwi.com by
  flight-number sequence, adding a Kiwi `priceSources[]` row and the `baggage` allowance. Itineraries with **no
  Kiwi match** keep `sourcesFound: 1` and `baggage: null` (honest, not faked); city-name (non-IATA) routes skip
  the Kiwi step.

### Pricing

Pay-per-event — billed only for records actually delivered:

| Event | Price |
|---|---|
| Run start | **$0.01** |
| Calendar day / fare | **$0.003** |
| Itinerary | **$0.005** |
| Place | **$0.001** |

Example: a 2-month cheapest-by-date calendar (~61 days) ≈ **$0.19**. Set a **Maximum cost per run** in the run
options to cap spend.

### Proxy

A proxy is required and the recommended default is preselected for each mode (country auto-pinned to
`market`); a cheaper override is available. An Apify account with a paid proxy plan is needed.

### Scope & honest notes

- Full **itineraries** are sourced from **Google Flights** (no key) and cross-priced against a second source,
  **Kiwi.com** — Skyscanner's own live itinerary search isn't reachable for no-login callers, so, like the
  leading flight-data actors, this actor aggregates alternative sources for the itinerary list. Every itinerary
  record discloses its `source`.
- The **calendar / search / places** modes are Skyscanner-native (cheapest-by-date, cheapest fares, place
  entities) — the differentiator over a plain itinerary scraper.
- `baggage` is filled only when an itinerary matches a Kiwi fare (roughly half of itineraries on IATA routes);
  otherwise it is `null`. Calendar/search fares are day-granular cheapest quotes, not per-minute itineraries.

### Legal

Scrapes only public, non-authenticated endpoints. No login, no personal data. You are responsible for
complying with the source sites' Terms of Service and applicable law. For lawful fare-tracking, route
discovery, price-alert and travel-content use.

# Actor input Schema

## `mode` (type: `array`):

Which engine(s) to run (combinable). 'itineraries' = FULL live flight list with exact times, per-segment flight numbers/airlines/aircraft, layovers, stop count, duration, price, cheapest/fastest/best tags, score and booking link (one-way, round-trip and multi-city) — sourced no-key from Google Flights (aliases: itinerary, flights, live). 'search' = Skyscanner cheapest fare(s) for a route on a specific date / date pair. 'calendar' = Skyscanner cheapest-by-date price grid across N months (aliases: cheapest-by-date, pricecalendar). 'places' = resolve an airport/city query to Skyscanner place entities (aliases: autosuggest).

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

Departure airport/city — 3-letter IATA code (e.g. 'JFK', 'LON') or city name. Aliases accepted: departureAirport, from.

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

Arrival airport/city — 3-letter IATA code (e.g. 'LAX') or city name. Required for search/calendar. Aliases accepted: arrivalAirport, to.

## `departDate` (type: `string`):

Outbound date for 'search' (YYYY-MM-DD). For 'calendar' it is the first month to fetch (day is ignored). If empty, calendar starts from the current month.

## `departDateEnd` (type: `string`):

Optional end of a departure-date range for 'search' (YYYY-MM-DD). When set, 'search' emits the cheapest fare for every day from departDate to departDateEnd (inclusive).

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

Return date (YYYY-MM-DD). When set, the trip is round-trip and prices are round-trip totals. Leave empty for one-way.

## `monthsAhead` (type: `integer`):

For 'calendar' mode: how many consecutive months (starting at departDate's month or the current month) to fetch, 1–12.

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

Number of adult passengers (16+).

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

Number of children (2–15). Informational passthrough for the Skyscanner deep link.

## `infants` (type: `integer`):

Number of infants on lap (under 2). Informational passthrough for the Skyscanner deep link.

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

Cabin of travel used in the Skyscanner deep link and query.

## `directOnly` (type: `boolean`):

Return only non-stop options. In 'itineraries' mode this searches Google Flights for 0-stop flights only; in 'search' mode the record's headline price becomes the cheapest direct price.

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

For 'itineraries' mode: maximum number of stops per itinerary (0 = non-stop only, 1 = up to one stop, etc.). Leave empty for any number of stops. 'directOnly' overrides this to 0.

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

For 'itineraries' mode: an ordered list of flight legs for a multi-city trip. Each item is an object {"origin":"JFK","destination":"LAX","date":"2026-10-15"}. When 2+ legs are given, the actor returns full itineraries for EVERY leg, grouped by a shared multiCityId (with legIndex/legCount). Overrides origin/destination/departDate.

## `strictAirport` (type: `boolean`):

For Skyscanner 'search'/'calendar' modes: Skyscanner's month grid can aggregate a whole city, so a JFK request may surface an EWR/LGA quote. When enabled, drop any fare whose actual operating origin/destination airport differs from the requested 3-letter IATA code. Regardless of this flag, each record exposes 'operatingOrigin'/'operatingDestination' and 'requestedOriginMatch'/'requestedDestinationMatch' so the real airport is always disclosed.

## `compareSources` (type: `boolean`):

For 'itineraries' mode: also query Kiwi.com (no key) as a second source and merge it into each matching itinerary. Adds a per-source price table (Google Flights + Kiwi with per-source booking links), recomputes bestPrice / cheapestSource / sourcesFound (>= 2 when a match is found), and fills the baggage allowance (carry-on / checked / personal) that Google's list endpoint does not expose. Disable to use Google Flights only.

## `roundTripReturnDetail` (type: `integer`):

For round-trip 'itineraries': how many top outbound options to expand with FULL return-leg detail. For each, a second Google Flights call (via an outbound-selection token) fetches the paired return itineraries, so each record carries BOTH legs (outbound + return, full segments/times/layovers) and the real round-trip total. 0 = fast mode: outbound options only at the round-trip total (no return-leg segments).

## `maxReturnsPerOutbound` (type: `integer`):

For round-trip 'itineraries' with return-leg detail on: the maximum number of paired return itineraries to emit for each expanded outbound option.

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

Skip fares/days whose cheapest price is above this amount (in the selected currency). 0 or empty = no cap.

## `resultSort` (type: `string`):

Client-side sort of the emitted records. 'date' = chronological; 'price' = cheapest first.

## `market` (type: `string`):

Skyscanner market / point-of-sale country code (e.g. 'US', 'GB', 'DE'). Also pins the proxy exit country. Aliases: skyscannerMarket, country.

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

ISO 4217 display currency for prices (e.g. 'USD', 'GBP', 'EUR'). Alias: skyscannerCurrency.

## `locale` (type: `string`):

Language/locale tag for place names (e.g. 'en-US', 'en-GB', 'de-DE'). Alias: skyscannerLocale.

## `placeQueries` (type: `array`):

Airport/city search terms or IATA codes to resolve to Skyscanner place entities (used by 'places' mode). E.g. \['London', 'JFK', 'Tokyo'].

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

Skyscanner flight search URLs (e.g. https://www.skyscanner.net/transport/flights/jfk/lax/261015/). The route, dates and cabin are parsed from each URL and scraped like a search input.

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

Maximum number of dataset records to emit across the whole run. 0 = no limit. Aliases: resultLimit, maxFlights, max\_results.

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

Maximum number of month/route requests fetched in parallel.

## `maxRequestRetries` (type: `integer`):

How many times to retry a blocked/failed request with a fresh proxy session before giving up on that month/route.

## `proxy` (type: `object`):

Proxy for the Skyscanner modes (search/calendar/places). A proxy is required; the recommended default is preselected and works reliably. The proxy country is auto-pinned to 'market'.

## `itineraryProxy` (type: `object`):

Proxy for the 'itineraries' mode. The recommended default returns results reliably; the country is auto-pinned to 'market'. Only used when 'itineraries' mode runs.

## Actor input object example

```json
{
  "mode": [
    "calendar"
  ],
  "origin": "JFK",
  "destination": "LAX",
  "departDate": "2026-10-15",
  "departDateEnd": "2026-10-20",
  "returnDate": "2026-10-22",
  "monthsAhead": 3,
  "adults": 1,
  "children": 0,
  "infants": 0,
  "cabinClass": "economy",
  "directOnly": false,
  "multiCityLegs": [],
  "strictAirport": false,
  "compareSources": true,
  "roundTripReturnDetail": 3,
  "maxReturnsPerOutbound": 6,
  "resultSort": "date",
  "market": "US",
  "currency": "USD",
  "locale": "en-US",
  "placeQueries": [],
  "startUrls": [],
  "maxItems": 200,
  "maxConcurrency": 4,
  "maxRequestRetries": 6,
  "proxy": {
    "useApifyProxy": true
  },
  "itineraryProxy": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped flight itineraries, calendar/fare records and place-search results.

# 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": [
        "calendar"
    ],
    "origin": "JFK",
    "destination": "LAX",
    "departDate": "2026-10-15",
    "monthsAhead": 3,
    "adults": 1,
    "cabinClass": "economy",
    "compareSources": true,
    "roundTripReturnDetail": 3,
    "market": "US",
    "currency": "USD",
    "locale": "en-US",
    "maxItems": 200,
    "proxy": {
        "useApifyProxy": true
    },
    "itineraryProxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("brilliant_gum/skyscanner-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": ["calendar"],
    "origin": "JFK",
    "destination": "LAX",
    "departDate": "2026-10-15",
    "monthsAhead": 3,
    "adults": 1,
    "cabinClass": "economy",
    "compareSources": True,
    "roundTripReturnDetail": 3,
    "market": "US",
    "currency": "USD",
    "locale": "en-US",
    "maxItems": 200,
    "proxy": { "useApifyProxy": True },
    "itineraryProxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("brilliant_gum/skyscanner-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": [
    "calendar"
  ],
  "origin": "JFK",
  "destination": "LAX",
  "departDate": "2026-10-15",
  "monthsAhead": 3,
  "adults": 1,
  "cabinClass": "economy",
  "compareSources": true,
  "roundTripReturnDetail": 3,
  "market": "US",
  "currency": "USD",
  "locale": "en-US",
  "maxItems": 200,
  "proxy": {
    "useApifyProxy": true
  },
  "itineraryProxy": {
    "useApifyProxy": true
  }
}' |
apify call brilliant_gum/skyscanner-scraper --silent --output-dataset

```

## MCP server setup

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