Google Flights has a date grid with a fare for every departure day, and a "track prices" toggle that emails you when its pick of dates moves. Both are fine for one trip. Neither gives you the table: every day, the fare, the airline and stops behind it, in rows you can sort, keep and put a threshold on. If your dates are flexible and you want the cheapest day to fly as data — or airfare price tracking that runs every morning — you need rows.
This is how to get one row per departure day from Google Flights as JSON, with no API key (there is no public Google Flights API), and how to turn it into a flight price alert.
1. One request, one row per day
The Flight Price Tracker on Apify takes routes, a first departure day and a window length. For each day it searches Google Flights, keeps that day's cheapest itinerary and ranks the days. A 30-day window on one route is at most 30 fare rows plus a free status row.
curl -X POST "https://api.apify.com/v2/acts/kestrel~flight-price-tracker/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"routes": ["LIS-LHR"], "departDate": "2026-10-05", "days": 30, "adults": 1, "currency": "USD", "market": "us"}'
A fare row:
{ "type": "fare", "route": "LIS-LHR", "trip": "one_way", "depart_date": "2026-10-05", "return_date": null,
"seat": "economy", "adults": 1, "currency": "USD", "price": 127, "price_display": "127 US dollars",
"airline": "Tap Air Portugal", "stops": 0, "depart_time": "8:00 PM", "arrive_time": "10:55 PM",
"duration": "2 hr 55 min", "duration_minutes": 175, "layovers": null, "co2_kg": 123,
"itineraries_seen": 12, "cheapest_in_window": true, "rank_in_window": 1,
"google_url": "https://www.google.com/travel/flights?tfs=...", "fetched_at": "2026-08-29T06:25:14+00:00" }
cheapest_in_window is true on exactly one day per route; rank_in_window orders the rest. The free status row repeats the headline as cheapest and cheapest_date, with days_searched, fares, filtered and no_results. For round trips, set tripLengthDays: 7: every day is priced as a week-long trip, price covering both legs.
2. The alert is a filter, not a diff
Set maxPrice and only days at or under it are delivered. The filter runs before billing, so a run that finds nothing under your line costs nothing — and the status row still reports the real cheapest, so you know how far off you are.
{ "routes": ["JFK-LHR", "EWR-LHR"], "departDate": "14 days", "days": 30, "maxStops": "nonstop", "maxPrice": 400, "currency": "USD" }
That is the whole flight price alert: a scheduled run with maxPrice, and a message whenever the dataset has a fare row. No stored previous price, no comparison code. Relative dates ("14 days", "6 weeks") keep a schedule looking the same distance ahead instead of going stale.
3. Python: a price history you own
import csv, os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("kestrel/flight-price-tracker").call(run_input={
"routes": ["LIS-LHR", "LIS-CDG"], "departDate": "30 days", "days": 30,
"maxStops": "one_or_fewer", "currency": "EUR", "market": "pt"})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
fares = [r for r in rows if r["type"] == "fare"]
with open("fare_history.csv", "a", newline="") as f:
w = csv.writer(f)
for r in fares: w.writerow([r["fetched_at"][:10], r["route"], r["depart_date"], r["price"], r["airline"], r["stops"], r["rank_in_window"]])
for r in rows:
if r["type"] == "status": print(r["route"], r["cheapest"], r["cheapest_date"], f"({r['fares']} of {r['days_searched']} days priced)")
Run it daily and each route and departure day gains one point per run — the flight price history Google keeps to itself. The window moves with the calendar, so today's rank-1 day can be compared with yesterday's.
4. A Telegram digest without code (n8n)
The n8n template Flight price alerts: cheapest day to fly on Google Flights → Telegram (n8n/ folder of kestrel-actors-examples) is six nodes: a 07:00 Schedule trigger, one HTTP Request to the run-sync endpoint, a Code node that finds the cheapest date per route and compares it with yesterday's in workflow static data, an IF for the drop threshold (0 = send daily, 5 = only drops of 5% or more), Telegram, and a NoOp. The message carries the cheapest date, airline, stops, the three cheapest dates and the google_url to book from.
As shipped, the template calls the sibling Google Flights Scraper, which returns every itinerary Google lists — up to three per date across 14 dates here, at $0.005 each, so at most $0.21 per route per day. Use that one to compare airlines and times on the same day. Pointing the HTTP node at the tracker makes the same digest 14 fare rows, with the Code node reading price and depart_date from them instead of the per-date status rows.
5. Cost and limits
- $0.004 per delivered
farerow. One route, 30 days: $0.12. Three routes daily for a month: about 2,700 rows, $10.80. An alert run that finds nothing: $0. - One row per day means one itinerary per day — the cheapest under your
seatandmaxStopsfilters. Ties go to the earlier day. - Fares differ by
marketandcurrency; set both to compare with your browser. A day priced in the wrong currency is reported, not billed. - The window is capped at 60 days per run; use two
departDatevalues for a longer horizon. - Prices include taxes and carrier fees as Google shows them, not baggage or seat fees.
That is the pipeline: one call for the days, maxPrice for the alert, a schedule for the history. Full input/output reference and FAQ on the actor page: apify.com/kestrel/flight-price-tracker.
Top comments (0)