A Python library for querying the reverse-engineered SkyScanner Android app API for flights, airports, locations, and car rentals, with built-in retries and error handling.
pip install curl_cffi typeguardimport datetime
from skyscanner import SkyScanner
from skyscanner.types import CabinClass, SpecialTypes
# Initialize the client
scanner = SkyScanner(
locale="en-US",
currency="USD",
market="US"
)
# Search for airports
airports = scanner.search_airports("London")
origin = airports[0] # First result
destination_airports = scanner.search_airports("New York")
destination = destination_airports[0]
# Search for flights
depart_date = datetime.datetime(2025, 8, 15)
return_date = datetime.datetime(2025, 8, 22)
response = scanner.get_flight_prices(
origin=origin,
destination=destination,
depart_date=depart_date,
return_date=return_date,
cabinClass=CabinClass.ECONOMY,
adults=2
)The main client class for interacting with Skyscanner APIs.
SkyScanner(
locale: str = "en-US",
currency: str = "USD",
market: str = "US",
retry_delay: int = 2,
max_retries: int = 15,
proxies: dict = {},
px_authorization: str | None = None,
verify: bool = True
)Parameters:
locale(str): Locale code for results (e.g., "en-US", "fr-FR")currency(str): Currency code for pricing (e.g., "USD", "EUR", "GBP")market(str): Market region code (e.g., "US", "UK", "DE")retry_delay(int): Seconds to wait between polling retriesmax_retries(int): Maximum number of polling retries before giving upproxies(dict): Proxy configuration for HTTP requestspx_authorization(str | None): Optional pre-generated PX authorization tokenverify(bool): Whether to verify SSL certificates
Search for flight prices between two locations.
get_flight_prices(
origin: Airport,
destination: Airport | SpecialTypes,
depart_date: datetime.datetime | SpecialTypes | None = None,
return_date: datetime.datetime | SpecialTypes | None = None,
cabinClass: CabinClass = CabinClass.ECONOMY,
adults: int = 1,
childAges: list[int] = []
) -> SkyscannerResponseParameters:
origin(Airport): Origin airport objectdestination(Airport | SpecialTypes): Destination airport or special search type (e.g., SpecialTypes.EVERYWHERE)depart_date(datetime | SpecialTypes | None): Departure date or SpecialTypes.ANYTIMEreturn_date(datetime | SpecialTypes | None): Return date (optional for one-way trips)cabinClass(CabinClass): Cabin class preferenceadults(int): Number of adult passengers (1-8)childAges(list[int]): Ages of child passengers (0-17 years, max 8 children)
Returns: SkyscannerResponse object containing flight options and pricing data
Raises:
ValueError: Invalid dates, passenger counts, or search parametersBannedWithCaptcha: When blocked by Skyscanner's anti-bot measuresAttemptsExhaustedIncompleteResponse: When max retries exceeded
Auto-suggest airports based on a search query.
search_airports(
query: str,
depart_date: datetime.datetime | None = None,
return_date: datetime.datetime | None = None
) -> list[Airport]Parameters:
query(str): Search text (airport name, city, or IATA code)depart_date(datetime | None): Optional departure date for contextreturn_date(datetime | None): Optional return date for context
Returns: List of Airport objects matching the query
Auto-suggest locations for car rentals and other services.
search_locations(query: str) -> list[Location]Parameters:
query(str): Location search text
Returns: List of Location objects
Retrieve a specific airport by its IATA code.
get_airport_by_code(airport_code: str) -> AirportParameters:
airport_code(str): Three-letter IATA airport code (e.g., "JFK", "LHR")
Returns: Airport object for the specified code
Raises:
GenericError: If airport code not found
Get detailed information for a specific flight itinerary.
get_itinerary_details(
itineraryId: str,
response: SkyscannerResponse
) -> dictParameters:
itineraryId(str): Unique itinerary identifier from search resultsresponse(SkyscannerResponse): Original search response containing session data
Returns: Dictionary with detailed itinerary information including flight legs and preferences
Search for car rental options between locations and times.
get_car_rental(
origin: Location | Coordinates | Airport,
depart_time: datetime.datetime,
return_time: datetime.datetime,
destination: Location | Coordinates | Airport | None = None,
is_driver_over_25: bool = True
) -> dictParameters:
origin(Location | Coordinates | Airport): Pickup locationdepart_time(datetime): Pickup date and timereturn_time(datetime): Drop-off date and timedestination(Location | Coordinates | Airport | None): Drop-off location (defaults to origin)is_driver_over_25(bool): Driver age flag affecting pricing
Returns: Dictionary containing car rental options and pricing
Parse a Skyscanner car rental URL and fetch rental options.
get_car_rental_from_url(url: str) -> dictParameters:
url(str): Skyscanner car hire URL
Returns: Car rental search results
Example URL format:
https://www.skyscanner.net/g/carhire-quotes/GB/en-GB/GBP/30/27544008/27544008/2025-07-01T10:00/2025-08-01T10:00/
Airport(
title: str, # Display name (e.g., "London Heathrow")
entityId: str, # Internal Skyscanner ID
skyId: str # IATA code (e.g., "LHR")
)Location(
name: str, # Location name
entity_id: str, # Internal ID
coordinates: str # Lat/long coordinates
)CabinClass.ECONOMYCabinClass.PREMIUM_ECONOMYCabinClass.BUSINESSCabinClass.FIRST
SpecialTypes.ANYTIME- Flexible date searchSpecialTypes.EVERYWHERE- Open destination search
The library defines several custom exceptions:
Raised when Skyscanner blocks requests with CAPTCHA challenges.
try:
response = scanner.get_flight_prices(origin, destination)
except BannedWithCaptcha as e:
print(f"Blocked by anti-bot measures: {e}")
# Consider using proxies or reducing request frequencyRaised when polling retries are exhausted without getting complete results.
try:
response = scanner.get_flight_prices(origin, destination)
except AttemptsExhaustedIncompleteResponse:
print("Search timed out - try again later")General API errors with status codes and response details.
import datetime
from skyscanner import SkyScanner
scanner = SkyScanner()
# Find airports
london_airports = scanner.search_airports("London")
heathrow = london_airports[0]
nyc_airports = scanner.search_airports("New York")
jfk = nyc_airports[0]
# Search flights
response = scanner.get_flight_prices(
origin=heathrow,
destination=jfk,
depart_date=datetime.datetime(2025, 9, 1),
return_date=datetime.datetime(2025, 9, 8),
adults=1
)from skyscanner.types import SpecialTypes
# Search from London to anywhere
response = scanner.get_flight_prices(
origin=heathrow,
destination=SpecialTypes.EVERYWHERE,
depart_date=SpecialTypes.ANYTIME
)# Search locations
locations = scanner.search_locations("London")
pickup_location = locations[0]
# Search car rentals
rentals = scanner.get_car_rental(
origin=pickup_location,
depart_time=datetime.datetime(2025, 7, 1, 10, 0),
return_time=datetime.datetime(2025, 7, 8, 10, 0),
is_driver_over_25=True
)- Use Proxies: Consider proxy rotation for high-volume usage
- Cache Results: Store airport/location searches to reduce API calls
- Validate Inputs: Check dates and passenger counts before API calls
- Reuse Px Authorization: X-Px-Authorization header isn't signel use. Once you've made one you can use it for multiple requests, once you get captcha though you need to switch ip and authorization
curl_cffi: HTTP client with browser fingerprintingtypeguard: Runtime type checkingorjson: Fast JSON parsing
- Add scraping flight prices from generic cities and not specific airports (like Milan and not MXP)
- Add async version
- Type better the flight price response to not always parse json
- Add method to build skyscanner buy link statically without requesting details