# Kiwi.com Scraper (`crawlerbros/kiwicom-scraper`) Actor

Scrape Kiwi.com - flight metasearch with virtual interlining. Search flights between any origin and destination, fetch popular routes from a city with live prices, and look up airports, cities and stations. Uses the public Kiwi.com GraphQL API. No auth, no proxy.

- **URL**: https://apify.com/crawlerbros/kiwicom-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Travel, Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Kiwi.com Scraper

Scrape **Kiwi.com** — the flight metasearch engine famous for virtual interlining (self-transfer connections between non-cooperating airlines). Search flights between any origin and destination, pull the most popular routes from a city with live prices, and look up airports, cities and stations. HTTP-only via the public Kiwi.com GraphQL API. No login, no cookies, no proxy required.

### What this actor does

- **Three modes:** `search` (flights by route + date), `popularRoutes` (top destinations from a city), `stationLookup` (airport / city / station autocomplete)
- **Live prices** in 32 currencies (ISO 4217)
- **Full itinerary details** — airlines, flight numbers, departure/arrival times, durations, stops, layovers, bag allowances, virtual-interlining flags
- **Four cabin classes** — Economy, Premium, Business and First
- **`anywhere` destination** — search flights from your origin to every destination Kiwi can price
- **Optional return date** — or let Kiwi return flights with any return date
- **Filters:** max stops, max price, keyword match, sort order
- **Empty fields are omitted** — you only ever see fields the API actually returned

### Output per flight (mode = `search`)

- `originCity`, `originAirport` (IATA code), `originAirportName`
- `destinationCity`, `destinationAirport`, `destinationAirportName`
- `departureTime`, `arrivalTime` (local times) plus `departureTimeUtc`, `arrivalTimeUtc`
- `durationMinutes`, `outboundDurationMinutes`, `stops`
- `layoverMinutes[]` — one entry per connection on the outbound journey
- `price`, `priceBeforeDiscount`, `currency`
- `airlines[]`, `airlineNames[]`, `flightNumbers[]`
- `includedHandBags`, `includedCheckedBags`, `hasNoCheckedBaggage`, `hasNoBaggageSupported`
- `isVirtualInterlining`, `isTrueHiddenCity`, `isThrowawayTicket`
- Return legs (when present): `isReturn`, `returnDepartureTime`, `returnArrivalTime`, `returnAirlines[]`, `inboundDurationMinutes`, `nightsInDestination`
- `provider` (e.g. `Kiwi.com`), `seatsLeft`
- `sourceUrl` — the exact Kiwi.com results page for this search
- `recordType: "flight"`, `scrapedAt`

### Output per popular route (mode = `popularRoutes`)

- `originCity`, `originAirport`, `destinationCity`, `destinationAirport`, `destinationCountry`
- `price`, `priceBeforeDiscount`, `currency`
- `sourceUrl` — Kiwi.com results page for the route
- `recordType: "popularRoute"`, `scrapedAt`

### Output per station (mode = `stationLookup`)

- `name`, `kind` (City / Airport & station / Country / …), `code` (IATA for airports, metro code for cities)
- `cityName`, `countryCode`, `countryName`, `airportsCount`
- `latitude`, `longitude`
- `id` — the Kiwi place id (`City:london_gb`, `Station:airport:LGW`) you can paste straight back into `origin` / `destination`
- `sourceUrl`, `recordType: "station"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string (select) | `search` | `search`, `popularRoutes` or `stationLookup` |
| `origin` | string | `london` | Airport code, city name or Kiwi place id (mode=search, popularRoutes) |
| `destination` | string | `paris` | Airport code, city name or Kiwi place id; use `anywhere` for all destinations (mode=search) |
| `stationQuery` | string | – | Free-text term (mode=stationLookup) |
| `travelDate` | string | today + 30 days | Departure date `YYYY-MM-DD` (mode=search) |
| `returnDate` | string | – | Optional return date `YYYY-MM-DD` (mode=search) |
| `currency` | string (select) | `usd` | 32 currencies (ISO 4217) |
| `stops` | string (select) | `any` | `any` / `nonstop` / `1plus` / `2plus` |
| `passengers` | int | `1` | 1–9 adults |
| `cabinClass` | string (select) | `economy` | `economy` / `premium` / `business` / `first` |
| `sortBy` | string (select) | `QUALITY` | Quality / price / duration / take-off / landing |
| `maxPrice` | number | – | Drop itineraries above this price |
| `containsKeyword` | string | – | Keep only flights matching this text (airline, flight number, city) |
| `maxItems` | int | `20` | Hard cap (1–500) |
| `proxyConfiguration` | object | – | Optional; only used lazily if the API rate-limits or blocks |

#### Example: cheap direct flights from London to Paris

```json
{
  "mode": "search",
  "origin": "london",
  "destination": "paris",
  "travelDate": "2026-09-15",
  "stops": "nonstop",
  "sortBy": "PRICE",
  "maxItems": 25
}
```

#### Example: popular routes from Dubai with return dates

```json
{
  "mode": "popularRoutes",
  "origin": "dubai",
  "currency": "aed",
  "maxItems": 10
}
```

#### Example: find the airport code for Osaka

```json
{
  "mode": "stationLookup",
  "stationQuery": "osaka",
  "maxItems": 5
}
```

#### Example: long-haul with a stop, any airline

```json
{
  "mode": "search",
  "origin": "LHR",
  "destination": "City:tokyo_jp",
  "travelDate": "2026-10-02",
  "stops": "any",
  "maxPrice": 900,
  "currency": "usd",
  "maxItems": 15
}
```

#### Example: business class to anywhere

```json
{
  "mode": "search",
  "origin": "london",
  "destination": "anywhere",
  "cabinClass": "business",
  "maxItems": 10
}
```

### Use cases

- **Travel price intelligence** — track how fares on a route evolve and detect virtual-interlining deals
- **Competitive fare monitoring** — compare Kiwi.com pricing against direct-airline prices
- **Route planning tools** — power "popular destinations from my city" widgets
- **Airport/city data enrichment** — resolve IATA codes, coordinates and country info for place names
- **Travel search engines** — feed real itineraries into metasearch prototypes

### Data source and limitations

- **Data source:** Kiwi.com's public GraphQL API (`api.skypicker.com/umbrella/v2/graphql`) — the same endpoint www.kiwi.com uses in your browser. No authentication is required.
- **Live prices:** flight fares are live quotes from Kiwi.com's fare engine. They change constantly and can be heavy to compute — searches can take 20–60 seconds for busy routes.
- **Anti-bot caveat:** Kiwi.com may rate-limit or block aggressive scraping (HTTP 429/403). The actor retries with backoff and can use Apify proxy if you enable it, but the actor is designed to work without a proxy.
- **One-way and multi-city:** this actor mirrors Kiwi's default search behaviour — a date-only search returns flights with any return date, exactly like www.kiwi.com. Multi-city and true one-way search shapes are not exposed.
- **Pagination:** the API returns one page of results per search (25–100 itineraries depending on filters). Kiwi's "show more" flow is interactive, so results are capped per search. Raise `maxItems` up to 100 for one page of results.
- **Sort caveat:** `TAKEOFF_ASC` and `LANDING_ASC` are valid Kiwi sort values but the return-search API returns no itineraries for them — use `QUALITY`, `PRICE` or `DURATION` for mode=search.
- **Date availability:** fares are only returned for dates Kiwi.com can price (typically up to ~11 months ahead). Dates in the past return zero results.
- **Not affiliated:** this actor is a third-party tool and is not affiliated with or endorsed by Kiwi.com.

### FAQ

**Do I need an API key or cookies?** No. The actor uses Kiwi.com's public GraphQL API, which requires no authentication.

**Why are prices higher than on kiwi.com?** Kiwi.com's pricing includes their service fees and can change between requests. The price shown is the live quote at scrape time.

**What does `isVirtualInterlining` mean?** Kiwi.com's signature feature — two flights on separate tickets (e.g. different airlines that don't cooperate) connected with a self-transfer. If it's `true`, the passenger must collect bags and check in again themselves; a checked bag is usually not included.

**Why are some fields missing on my records?** All fields are omitted when the API doesn't return them (no sentinel values). For example `returnDepartureTime` only appears when the search includes a return leg, and `layoverMinutes` only for connecting flights.

**Can I scrape prices for a whole month?** Not in one call — each search covers a single departure date. Run the actor per date and merge the datasets.

**Is this affiliated with Kiwi.com?** No — this is a third-party actor using Kiwi.com's public API.

# Actor input Schema

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

What to fetch.

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

Airport code, city name, or Kiwi place ID (mode=search, popularRoutes). Examples: `LTN`, `london`, `City:london_gb`.

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

Airport code, city name, or Kiwi place ID (mode=search). Use `anywhere` to search all destinations.

## `stationQuery` (type: `string`):

Free-text term to search airports, cities, countries and points of interest (mode=stationLookup).

## `travelDate` (type: `string`):

Departure date (mode=search). Format `YYYY-MM-DD`. When omitted, the actor uses today + 30 days.

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

Optional return date (mode=search). Format `YYYY-MM-DD`. When omitted, Kiwi returns flights with any return date.

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

Currency for all prices (ISO 4217).

## `stops` (type: `string`):

Filter itineraries by the number of stops on the outbound journey.

## `passengers` (type: `integer`):

Number of adult passengers (1-9).

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

Cabin class for the search (mode=search, popularRoutes).

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

How Kiwi.com sorts the returned itineraries.

## `maxPrice` (type: `number`):

Drop itineraries priced above this amount (in the selected currency).

## `containsKeyword` (type: `string`):

Only keep flights whose airline, flight number, origin or destination contains this text (case-insensitive).

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

Hard cap on emitted records.

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

Optional Apify proxy. The actor runs without a proxy and only uses it lazily if the Kiwi API starts rate-limiting (429) or blocking (403).

## Actor input object example

```json
{
  "mode": "search",
  "origin": "london",
  "destination": "paris",
  "currency": "usd",
  "stops": "any",
  "passengers": 1,
  "cabinClass": "economy",
  "sortBy": "QUALITY",
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `flights` (type: `string`):

Dataset containing all scraped Kiwi.com flights, popular routes and station lookups.

# 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": "search",
    "origin": "london",
    "destination": "paris",
    "currency": "usd",
    "stops": "any",
    "passengers": 1,
    "cabinClass": "economy",
    "sortBy": "QUALITY",
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/kiwicom-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": "search",
    "origin": "london",
    "destination": "paris",
    "currency": "usd",
    "stops": "any",
    "passengers": 1,
    "cabinClass": "economy",
    "sortBy": "QUALITY",
    "maxItems": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/kiwicom-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": "search",
  "origin": "london",
  "destination": "paris",
  "currency": "usd",
  "stops": "any",
  "passengers": 1,
  "cabinClass": "economy",
  "sortBy": "QUALITY",
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call crawlerbros/kiwicom-scraper --silent --output-dataset

```

## MCP server setup

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