Google Flights Price Fetcher - route & date search avatar

Google Flights Price Fetcher - route & date search

Pricing

from $0.20 / 1,000 results

Go to Apify Store
Google Flights Price Fetcher - route & date search

Google Flights Price Fetcher - route & date search

Fetch real Google Flights offers as clean JSON: carrier, times, stops, segments, price. Plain HTTP, no browser needed. Batch several routes in one run. Every run ends with a RUN_SUMMARY row saying exactly what happened: complete, timed out, rate limited, or zero match. Priced per flight row.

Pricing

from $0.20 / 1,000 results

Rating

0.0

(0)

Developer

T2 Solutions

T2 Solutions

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Google Flights Price Fetcher — route & date search

Fetch real flight offers from Google Flights for an origin → destination, one day or a round trip: carrier, flight times, aircraft, stops, segment detail and the price Google shows — as clean JSON, one row per offer, ready for Sheets, databases or an agent pipeline.

No headless browser. No login. No proxies. One paced plain-HTTP request per search, exactly like a human tab — because that is what works: Google serves the full offer data server-rendered in the results page, and this actor parses it with a fixture-pinned, test-verified layout contract.

Why use this actor

  • 🎯 The price Google shows — the number a shopper sees, not an inferred estimate. Plus each offer's segment list (flight numbers, aircraft) when it's a multi-leg trip.
  • ⚡ Plain HTTP, no browser spin-up — most rivals run Puppeteer/Playwright; that burns compute and adds flakiness. This one reads the page like the Transport you already have: one GET per search.
  • 🧾 It reports its own honesty — every run ends with exactly one RUN_SUMMARY row (complete / partial / timed_out / zero_match), so an empty result set never masquerades as a success.
  • 🧮 Batch input — search several routes in one run with a shared fail-safe deadline.
  • 🤖 Agent-ready — deterministic JSON (offerId fingerprints are stable across runs), LIMITED_PERMISSIONS-compatible, and an MCP section below: an agent can drive it unattended.
  • 🛡️ Fail-safe deadline — never hangs past a wall you set; partial results are flushed and honestly labeled instead of vanishing.

Input

FieldTypeDefaultDescription
jobsarray of objects (required)—One or more route jobs (see below).
failSafeDeadlineMinutesinteger55Hard wall for the whole run. On expiry running stops, fetched rows are kept, and RUN_SUMMARY records timed_out. A value ≤ 0 fails fast.
pacingSecondsinteger20Seconds between search fetches (min 5). Higher is gentler; lower is faster.
maxOffersinteger200Flight rows kept per job (Google returns best-first; the cap applies after that order).

Job object (route type)

FieldTypeDescription
typestring"route" (default). A "calendar" job is accepted but completes as an explicitly-null calendar entry with a documented reason in RUN_SUMMARY.calendarUnavailable (v1 scope: routes).
labelstringYour name for the job; shows up on every row. Default job-N.
originstring (required)Origin airport/city code, e.g. JFK.
destinationstring (required)Destination code, e.g. LAX.
departureDatestring (required)YYYY-MM-DD.
returnDatestring (optional)Return date for round trips (on X through Y). Omit for one-way.
cabinstring (optional)ECONOMY (default), PREMIUM_ECONOMY, BUSINESS, FIRST.
passengersinteger (optional)1–9; appended as N adults when > 1.
maxOffersinteger (optional)Per-job cap, overriding the global maxOffers for this job only.

Example input — three routes in one run:

{
"jobs": [
{ "type": "route", "label": "jfk-lax-rt", "origin": "JFK", "destination": "LAX",
"departureDate": "2026-11-07", "returnDate": "2026-11-14" },
{ "type": "route", "label": "sfo-nrt-jan", "origin": "SFO", "destination": "NRT",
"departureDate": "2027-01-10", "returnDate": "2027-01-20", "cabin": "BUSINESS" },
{ "type": "route", "label": "mia-gru-oneway", "origin": "MIA", "destination": "GRU",
"departureDate": "2026-11-21" }
],
"failSafeDeadlineMinutes": 55
}

Output

One row per flight offer (columns per the table), then exactly one final RUN_SUMMARY row.

ColumnNullableNotes
recordTypenoAbsent on offer rows; "RUN_SUMMARY" on the final row.
offerIdnoStable fingerprint (route + times + carrier + price + flight number) — identical queries across runs give identical IDs, so agents can diff price changes.
jobLabelnoThe job's label.
origin / destinationnoIATA codes as parsed from the offer.
departureAt / arrivalAtnoLocal (airport-local) time, ISO-like YYYY-MM-DDTHH:MM:SS.
durationMinutesyesComputed from the offered times (minutes).
stopsyes0 = nonstop.
segmentsyesFor multi-leg trips: per-segment airports, times, dates, flight number, aircraft. null when not published.
carrieryesDisplay name (e.g. "Delta"), else the code.
priceUsdno (skipped rows counted)The price Google shows.
pricePerPassengerUsdalways nullNo per-passenger split is published; we don't invent numbers.
bookingUrlalways nullGoogle's booking blob is opaque, not a URL; we don't fabricate links.
fareBrandalways nullNot exposed by the results page payload.
fetchedAtnoUTC timestamp of the fetch.

RUN_SUMMARY (the honesty row)

FieldMeaning
statecomplete · partial (some jobs failed or input was dropped) · timed_out (deadline wall) · zero_match (every job fetched fine but Google returned no offers)
rowsRequested / rowsFetchedCapped demand vs what was delivered.
jobsTotal / jobsOk / jobsFailedPer-job counts.
partialReasondeadline · rate_limited · parse_failure · job_cap · row_cap · input_invalid · …
calendarUnavailableCalendar-type jobs with the documented v1 reason (explicitly-null calendar, never an error loop).
jobResultsPer-job outcome: rows, skipped/unparsed/duplicate offer counts.

Zero-match example (a real empty run — an agent should read this, not panic):

{
"recordType": "RUN_SUMMARY",
"state": "zero_match",
"rowsRequested": 200,
"rowsFetched": 0,
"jobsTotal": 1,
"jobsOk": 1,
"jobsFailed": 0,
"partialReason": null,
"calendarUnavailable": null,
"jobResults": [ { "label": "jfk-lax", "status": "ok", "rows": 0 } ]
}

Charging matches this row: you pay per flight row (result event); a zero-match run charges zero results.

Use with AI agents (MCP)

Every Apify actor is callable by AI agents — this one is built to behave when they drive it:

  • Apify MCP server — add https://mcp.apify.com as an MCP server in your agent (Claude, Cursor, etc.), authenticate with an Apify API token, and this actor appears as a tool whose input is the plain JSON schema above.

  • REST — one call starts a run, one call reads the results:

    curl -X POST "https://api.apify.com/v2/acts/YOUR~google-flights-price-fetcher/runs?token=YOUR_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"jobs":[{"origin":"JFK","destination":"LAX","departureDate":"2026-11-07"}]}'
    # results: GET /v2/acts/YOUR~google-flights-price-fetcher/runs/{runId}/dataset/items?token=YOUR_TOKEN
  • Safe to hand over — the actor runs under Apify's LIMITED_PERMISSIONS: a run can only do what a run needs (its own dataset and key-value store, plus the Google Flights page it fetches), nothing else in your account.

  • It reports its own honesty — the RUN_SUMMARY row means an agent can tell a complete scan from a timed-out, rate-limited, invalid-input or zero-match one without guessing from an empty dataset.

  • Batch input — "jobs": [ {...}, {...} ] resolves several routes in one call, which is how agents usually want to use it.

Migrating from another Google Flights scraper?

An honest comparison — including where another tool may still be right. (Figures are what the respective Store pages showed in our late-October 2026 recon; verify live stats yourself.)

If you're onWhat changes
kaix/google-flights-scraper (volume leader)Cheaper per flight ($0.00006) and hugely popular — but no rating and no review presence. This actor is for agents who need the RUN_SUMMARY honesty contract and stable offerIds more than the absolute floor price.
johnvc/Google-Flights-Data-ScraperPriced per page ($0.03/page); this one is per flight row, and you can cap rows per job.
memo23/google-flights-scrapermemo23 is the field's README/quality bar; this actor answers with plain-HTTP speed (no browser compute), per-row pricing, and the agent-facing honesty row.
lergassy/google-flights-scraperStrongest rated (4.86★/11); a fair pick if breadth of output fields matters more than pacing control and batch deadlines.
automation-lab/google-flights-scraper~40% of runs were failing in our snapshot — the actor's core problem. Every run here ends in a state that says what actually happened.

Not the right tool if: you need fare-class breakdowns, seat maps, or per-passenger price splits — Google's results-page payload doesn't publish them and we won't invent them.

Pricing (proposed — pending publish sign-off)

Pay-per-event: you pay per flight row delivered, and a zero-match run charges zero results.

Price per flight row
This actor (proposed)$0.0002
Field floor (kaix)$0.00006
Field median~$0.002
Per-page rivals$0.03/page

Why $0.0002: at ~1–30 offers per typical route query, a single-route run lands around $0.0004 – $0.006 — below the field median, well above the floor, and comfortably positive after 80% revenue share and platform usage (~25 s of 1-GB compute per search at one request per ~20 s pacing ≈ $0.00003 usage per search, so every event keeps >8× its usage). Final number is decided at publish time (see the control-plane MONEY.md margin check).

FAQ

How fresh are the prices? As fresh as a search: one paced GET per job at run time. Prices are Google's own snapshot from your run's moment, not a cached feed.

Does this hit rate limits? Pacing defaults to 20 s between searches with 30/120/300 s backoff on a rate limit — the same posture Google demonstrably tolerates for normal users (verified with a 20-request sustained probe over 8 minutes: 100% clean). A rate-limited job is retried, then recorded as partialReason: rate_limited, never silently dropped.

Round trips? Yes — set returnDate. The search covers the pair in one query, exactly as the site does.

Can I get the price calendar (cheapest by date)? Not yet. Calendar-type jobs are accepted and complete with an explicitly-null calendar plus a documented reason in RUN_SUMMARY.calendarUnavailable — it's the honest "not built yet", not an error.

Can I localize? The query pins hl=en&curr=USD (defaults); cabin and passengers are honored. Non-USD/localized output is on the roadmap.

Something failed mid-run. Read RUN_SUMMARY: jobsFailed and per-entry reason tell you which route and why. Partial runs keep the rows that succeeded.

Development (this repo)

python test_fetcher.py # 39 tests — fixture-pinned layout contract + transport
python test_main_wiring.py # 26 tests — run orchestration with a fake SDK
python -m main # local run with INPUT.json in cwd

Design/parity docs: _bmad-output/architecture.md (endpoint choice, failure-mode table, charging, caps), _bmad-output/fixture-flights-jfk-lax.html (golden page the parse paths are pinned to), spec in _bmad-output/specs/spec-google-flights-scraper/.