---
title: "Flight price scraping"
description: "Scraping flight prices and award seats from airline sites and OTAs like Kayak and Google Flights: fares by route, date and cabin, through Akamai."
canonical: https://www.zenrows.com/use-cases/scraping-flight-prices
updated: 2026-10-18
---

# Flight price scraping

Scraping flight prices means running fare searches on airline websites and online travel agencies and recording each fare by route, date, cabin and fare class. Zenrows fills the search form, gets through Akamai and other protection on airline sites, and returns the results as JSON or captured API responses, ready for fare tracking and alerts.

## Sample output: flight prices for one route

```json
{
  "search": {
    "origin": "JFK",
    "destination": "LHR",
    "depart": "2026-12-18",
    "return": "2027-01-04",
    "passengers": 1,
    "cabin": "economy",
    "point_of_sale": "us"
  },
  "source": "airline.example.com",
  "searched_at": "2026-10-17T07:40:00Z",
  "currency": "USD",
  "itineraries": [
    { "flights": ["XX101", "XX118"], "stops": 0, "fare_brand": "Basic", "fare_class": "N", "price": 684.0, "seats_left": 4, "bag_included": false },
    { "flights": ["XX101", "XX118"], "stops": 0, "fare_brand": "Main", "fare_class": "L", "price": 789.0, "seats_left": null, "bag_included": true },
    { "flights": ["XX205", "XX230"], "stops": 1, "fare_brand": "Main", "fare_class": "Q", "price": 712.0, "seats_left": 7, "bag_included": true }
  ],
  "award": { "program": "Example Miles", "cabin": "business", "miles": 57500, "taxes": 5.6, "available": true },
  "lowest_price": 684.0
}
```

An illustrative round trip from an airline's own search, cash fares and an award seat side by side. Store `searched_at` and `point_of_sale` with every fare, because the same search costs a different amount tomorrow and in another country.

## What flight price teams collect

Fare data is a grid of route, departure date, return date, cabin and passenger count, run against each seller. The jobs below differ in which part of that grid matters and how fast it has to refresh.

| Job | Data you collect | Typical sources |
|---|---|---|
| Fare tracking and price alerts | Lowest fare per route and date, refreshed several times a day | Google Flights, Kayak, Skyscanner, airline sites |
| Award seat alerts | Miles price, taxes and availability by cabin for loyalty redemptions | Airline loyalty programs such as LATAM Pass, Smiles, AAdvantage |
| Airline revenue benchmarking | Competitor fares by fare brand and fare class on shared routes | United, Lufthansa, Turkish Airlines, British Airways, Air India |
| OTA versus direct price checks | Same itinerary priced on the airline and on several OTAs | Airline sites, Expedia, MakeMyTrip, Goibibo |
| Holiday package pricing | Flight plus hotel package price by departure airport and date | Tour operators such as TUI, Virgin Atlantic Holidays |
| Fare history datasets | Daily price snapshots per route for forecasting models | Any of the above, stored over months |

## Why airline websites block flight scrapers

Every fare search on an airline site queries a reservation system that costs the airline money, so airlines protect search hard. Large carriers commonly sit behind bot management such as Akamai, and some show a challenge page between the search and the results.

| What breaks | What it looks like | How Zenrows handles it |
|---|---|---|
| Akamai bot management | Searches work for a day or two, then every request returns access denied | Zenrows' stealth and retries get through [Akamai](/bypass/akamai) and similar bot management |
| Search form before any fare | Fares appear only after typing airports, picking dates and pressing search | Page actions fill and submit the form in Fetch before the page is returned; [Browser](/products/browser) drives longer flows with Playwright |
| Fares in background API calls | The results page is drawn from a JSON response, not from HTML you can parse | Fetch captures the page's background network calls (XHR), so you read the fare JSON directly |
| Challenge pages | A CAPTCHA or Turnstile page appears instead of the results | Adaptive Stealth Mode escalates to browser rendering and stealth when a challenge page appears, and gets the search through it |
| Point-of-sale fares | The same seat is priced differently by visitor country and currency | Geotargeting runs each search from the country you are tracking |
| Award searches behind a login | Miles availability shows only to signed-in loyalty members | A Browser session keeps cookies across the login and the award search |

## How to scrape flight prices with Zenrows

1. **Pick routes and dates.** List the airport pairs, departure and return dates, cabin and passengers. Where the site puts the search in the URL, build URLs directly.
2. **Run the search.** For URL-driven searches, send the URL to Fetch with Adaptive Stealth Mode. For form-driven searches, use a full browser render with page actions that fill airports and dates and click search.
3. **Read the fares.** Capture the page's background network calls to read the airline's own fare response, or name the fields on the results list with CSS selectors.
4. **Use Browser for long flows.** Logins, award calendars and multi-page booking steps run in a Browser session with Playwright or Puppeteer.
5. **Repeat on a schedule.** Submit the URL grid to Batch and store each fare with the time and market it was seen in.

```python Python
# pip install requests
import json
import requests

AIRLINE_SEARCH_URL = "https://airline.example.com/search"  # placeholder

instructions = [
    {"wait_for": "#origin"},
    {"fill": ["#origin", "JFK"]},
    {"fill": ["#destination", "LHR"]},
    {"fill": ["#depart-date", "2026-12-18"]},
    {"click": "button[type='submit']"},
    {"wait_for": ".fare-results"},
]
params = {
    "apikey": "YOUR_ZENROWS_API_KEY",
    "url": AIRLINE_SEARCH_URL,
    "js_render": "true",
    "premium_proxy": "true",
    "proxy_country": "us",
    "js_instructions": json.dumps(instructions),
    "json_response": "true",  # returns the fare API calls the page made
}
response = requests.get("https://api.zenrows.com/v1/", params=params)
print(response.json())
```

```javascript Node.js
// npm install playwright
import { chromium } from "playwright";

const LOYALTY_LOGIN_URL = "https://airline.example.com/login";  // placeholder
const AWARD_SEARCH_URL = "https://airline.example.com/award-search?from=GRU&to=LIS&date=2026-12-18";

const browser = await chromium.connectOverCDP(
  "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY&proxy_country=br"
);
const page = await browser.newPage();

// Capture the award search response instead of parsing the page
page.on("response", async (res) => {
  if (res.url().includes("/award-search")) console.log(await res.json());
});

await page.goto(LOYALTY_LOGIN_URL);
await page.fill("#member-id", process.env.MEMBER_ID);
await page.fill("#password", process.env.MEMBER_PASSWORD);
await page.click("button[type='submit']");
await page.goto(AWARD_SEARCH_URL);  // route, date and cabin in the URL
await page.waitForSelector(".award-calendar");
await browser.close();
```

```bash CLI
npx -y @zenrows/cli init
# A URL-driven search, rendered from the US market
zenrows fetch "FLIGHT_SEARCH_URL" --proxy-country us --wait-for ".fare-results" --output markdown
# The full route and date grid as one job
zenrows batch create fare-grid.jsonl --wait
zenrows batch results JOB_ID --out fares.jsonl
```

```text Claude Code (MCP)
# Connect once
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp

# Then ask:
Use Zenrows to open Google Flights, search a one-way economy flight for one adult from JFK to LHR on 18 December 2026, and return the five cheapest options with airline, departure and arrival times, stops and price in USD.
```

## Which Zenrows product fits

| If you need to | Use | Why |
|---|---|---|
| Price a route on a site with searchable URLs | [Fetch](/products/fetch) | One request returns the rendered results or the fare JSON |
| Fill an airline's search form in one request | [Fetch](/products/fetch) with page actions | Fills airports and dates, clicks search and waits for results |
| Search award seats behind a login, or a flow with many steps | [Browser](/products/browser) | A real browser session you control with Playwright or Puppeteer |
| Refresh thousands of route and date searches a day | [Batch](/products/batch) | Runs the full fare grid as one job, results by webhook |

## What success looks like

| Measure | What good looks like | How to check it |
|---|---|---|
| Search success per airline | Most searches on each carrier return fares, measured per site rather than averaged | Log successful searches over attempts per airline, per day |
| Fare match | The fare you stored equals what a traveller sees for the same search and market | Re-run a sample of routes by hand and compare price and fare brand |
| Alert lead time | A fare drop reaches your users within one refresh cycle | Measure time from `searched_at` to alert sent |
| Grid coverage | Every route and date in your grid has a fare or an explicit no-availability result | Count empty cells per carrier per run |
| Response time | Single searches return fast enough for an on-demand price check | Track response time per request in your logs |
| Grid run time | The full route and date grid finishes inside one refresh window | Log the start and end time of each Batch job |

## Flight price scraping FAQ

### How do I scrape flight prices?

Start from the search the airline or OTA runs. If the route and dates are in the URL, send that URL to Fetch with Adaptive Stealth Mode. If the site needs a form, add page actions that fill it and click search. Read fares from the page's captured background calls, or from the results page with CSS selectors.

### Can I scrape Google Flights?

Yes. Google Flights renders results with JavaScript, so fetch it with Adaptive Stealth Mode and geotargeting that matches the market you are pricing. A common pattern is to find the cheapest seller for a route on Google Flights, then price that airline directly for fare class and baggage details.

### Why are airline websites so hard to scrape?

Each search queries a reservation system, so airlines protect it. Large carriers commonly use bot management such as Akamai, which learns request patterns over days and then blocks them. Airline pages also load fares from background calls and can show a challenge page before the results. Adaptive Stealth Mode starts with the lightest setup and escalates to browser rendering and stealth only when an airline page needs it.

### Is there a flight price API I can use instead of scraping?

Airline distribution APIs and GDS access exist, but they require commercial agreements and rarely include award seats, the airline's own web-only fares, or OTA prices. A flight price tracker API built on Zenrows returns what each website shows the public, for any route and market you search.

### Can I track award seats and miles prices?

Yes. Award searches often need a signed-in loyalty account. Open a Browser session, sign in with your own credentials, run the award search and capture the response. Store miles, taxes and cabin per date, then compare runs to send alerts when award seats open.

### How do I monitor flight prices over time?

Fix a grid of routes, dates and markets, and run it on a schedule with Batch: several times a day for close-in departures, daily for dates months out. Store each fare with its search time, point of sale and fare brand, then compare runs to spot drops. Alert on a change against the last run rather than on a fixed price.

### Is scraping flight prices legal?

Public fares shown without a login are widely collected for price comparison and research. Read each airline's terms of use, only sign in to accounts you are entitled to use, and keep request volumes reasonable. For your own case, check with your legal team.

## Related use cases

- [Travel data scraping](https://www.zenrows.com/use-cases/travel-data-scraping.md): Fares, room rates, car hire quotes, tour prices and reviews from airlines, OTAs and travel marketplaces.
- [Hotel data scraping](https://www.zenrows.com/use-cases/hotel-data-scraping.md): Nightly rates, room types and parity gaps from Booking.com, Expedia, Google Hotels and brand sites.
- [Dynamic pricing data](https://www.zenrows.com/use-cases/dynamic-pricing.md): Live competitor price, stock and demand inputs for a repricing engine, on demand or on a schedule.
- [Competitor price scraping](https://www.zenrows.com/use-cases/price-scraping.md): Competitor prices, promotions, shipping and stock per SKU from retailers and marketplaces, refreshed on your schedule.
- [Browser automation](https://www.zenrows.com/use-cases/browser-automation.md): Logins, portal lookups and report downloads run in a cloud browser your Playwright or Puppeteer code drives.

Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
