Skyscanner Flight Scraper
Under maintenancePricing
Pay per usage
Skyscanner Flight Scraper
Under maintenanceScrapes Skyscanner flights via the internal web-unified-search JSON API — no browser needed (pure HTTP over residential proxy). Mirrors the jupri/skyscanner-flight technique.
Skyscanner Flight Scraper (Apify Actor)
Scrapes Skyscanner flights via its internal web-unified-search JSON API — no browser
in the hot path — over Apify's built-in Residential Proxy. Same technique as
jupri/skyscanner-flight.
input → resolve IATA→entityId → mint cookie → POST web-unified-search → poll until complete → parse → dataset
Why no browser
Skyscanner's web-unified-search endpoint returns pure JSON. The only obstacle is the
PerimeterX cookie (_px3). A clean residential IP usually gets a usable cookie with a
plain HTTP GET (Phase 1). If that IP is challenged, the actor falls back to a headless
anti-detect browser (Camoufox, Phase 2) that loads one page from the same sticky IP
and hands back the cookie. Everything else is HTTP.
Input
Mirrors jupri's fields. Minimum: origin.0, target.0, depart.0.
| Field | Meaning |
|---|---|
origin.0..5 / target.0..5 / depart.0..5 | Per-leg origin, destination, and YYYY-MM-DD date. For a round trip: leg 0 = outbound, leg 1 = origin.1=target.0, target.1=origin.0, depart.1=return. |
market / currency | ISO country + currency (e.g. IL / USD). currency is required internally. |
sort | score | cheapest | fastest | departure. |
cabin_class | economy | premiumeconomy | business | first. |
adults / children / infants | Passenger counts (max 8 each). |
non_stop / one_stop / two_stop | Stop filters (any combination). |
limit | Slice the result count. |
dev_proxy_config | Proxy. Defaults to Apify RESIDENTIAL (needed to pass PerimeterX). |
dev_custom_headers / dev_custom_cookies | Extra headers / cookies (inject a pre-minted _px3 here). |
dev_transform_fields / dev_no_strip / dev_dataset_name / dev_dataset_clear | Output shaping. |
Example:
{"origin.0": "TLV", "target.0": "HER", "depart.0": "2026-08-02","origin.1": "HER", "target.1": "TLV", "depart.1": "2026-08-05","market": "IL", "currency": "USD","cabin_class": "economy", "adults": 1, "non_stop": true,"sort": "cheapest"}
Output
One dataset record per itinerary:
{"id": "16995-2608021920--30967-0-12130-2608022110|12130-2608051125--30967-0-16995-2608051305","price": 229, "currency": "USD","carriers": "Blue Bird Airways","stops": 0,"origin": "TLV", "destination": "HER","departure": "2026-08-02T19:20", "arrival": "2026-08-02T21:10","durationMinutes": 110,"legs": [ … ], "agents": [ … ]}
id is the legOut|legIn config id — the key for a per-agent price lookup
(/g/sonar/v3/itinerary/details/poll).
Run
Locally (needs Apify CLI + an APIFY token for proxy):
$apify run --purge
Deploy:
$apify push
Call it over the API (this is how the .NET admin consumes it):
curl -X POST \"https://api.apify.com/v2/acts/<actor-id>/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \-H 'Content-Type: application/json' \-d '{"origin.0":"TLV","target.0":"HER","depart.0":"2026-08-02","market":"IL","currency":"USD"}'
Gotchas baked in
user-agenton the search POST must match the UA the cookie was minted with (Phase 2 returns the browser's exact UA for this reason).x-skyscanner-currencyis required (missing →400).- Mint + every fire exit the same sticky IP (PerimeterX binds
_px3to the IP). - First response ≈ 10 results (
status: incomplete); it grows toward ~860 as the actor polls tocomplete.