Search Google Flights by Route, Date, and Cabin

Site google.comTask search-google-flightsVersion v21Updated Sep 24, 2026Category travel

Search Google Flights for one-way or round-trip itineraries with specified airports, dates, cabin, airlines, currency, and locale, then extract visible flight cards without booking or entering passenger information. This skill was captured from a live agent session on google.com and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Given {origin}, {destination}, {center-date}, an optional {date-offset-days}, {cabin}, {airlines}, {trip-type}, {currency}, and {locale}, search Google Flights directly and return currently rendered flight options. Support a date window by searching each requested date, deduplicating results, and preserving the searched date. Extract airline, flight number, departure and arrival airports/times, duration, stops, price, and card evidence when visible. Do not book, select a flight for purchase, sign in, or enter passenger data.

Use Cases

  • Finding one-way or round-trip flight options between caller-specified airports.
  • Searching a date or bounded date window such as {center-date} ± 2 days.
  • Restricting results to a requested cabin and a visible list of airlines.
  • Returning current prices, schedules, durations, and stop counts without checkout.
  • Reusing one browser session for several date searches to reduce connection and startup overhead.

Automation Flow

  1. Construct the direct Google Flights URL; do not visit the Google homepage or type into search controls:
https://www.google.com/travel/flights?q={url-encoded-query}&curr={currency}&hl={locale}

Use a natural-language query equivalent to:

One way flights from {origin} to {destination} on {YYYY-MM-DD} {cabin}
Round trip flights from {origin} to {destination} on {YYYY-MM-DD} returning {YYYY-MM-DD} {cabin}

A round trip needs both dates in the query. Sending one date makes Google resolve its own return, so the results are not the caller's itinerary. If the caller gives no return date, run the one-way form and say the search was one-way.

For example, the observed durable form is /travel/flights?q=One%20way%20flights%20from%20{origin}%20to%20{destination}%20on%20{date}%20{cabin}&curr=USD&hl=en. Replace all values with caller inputs; never retain an observed airport pair or date as a skill constant.

  1. For a date window, compute the ISO dates locally from {center-date} and {date-offset-days}. Navigate directly to one URL per date, preferably in the same browser session. Do not use the homepage or calendar controls when a direct query URL can express the date. Wait about 6 seconds after domcontentloaded for dynamic flight cards.

  2. Google Flights has no confirmed reusable URL parameter for airline restrictions. If exact airline filtering is required, after the page renders use the visible Airlines button, then the dialog's role="switch" and airline checkbox rows. Turn off Select all airlines, select only the visible requested airline names, close the dialog, and wait for results to refresh. The observed airline labels included Air Europa, American, and TAP Air Portugal; match caller-supplied names case-insensitively and do not fabricate a carrier label. When avoiding another interaction is preferable, extract the rendered cards and retain only cards whose visible airline text matches {airlines}.

  3. If a visible View more flights button exists, click it once and wait roughly 4–5 seconds before extraction. Do not use booking, select-flight, checkout, or passenger controls. Google may expose additional dates through navigation buttons, but for a bounded date window prefer direct URLs for each date and record the searched date rather than relying on stateful date navigation.

  4. Run this self-contained evaluator on each loaded results page after any requested airline filter has been applied, replacing its currency with {currency}:

(()=>{const clean=s=>(s||'').replace(/\s+/g,' ').trim();const visible=e=>!!e&&(e.offsetWidth||e.offsetHeight||e.getClientRects().length)>0;const u=new URL(location.href),body=clean(document.body?.innerText);const q=u.searchParams.get('q')||'';const date=(q.match(/\b(20\d{2}-\d{2}-\d{2})\b/)||[])[1]||null;const blocked=/captcha|unusual traffic|verify you are human|automated queries|sign in/i.test(body)&&!document.querySelector('li.pIav2d');const cards=[...document.querySelectorAll('li.pIav2d')].filter(visible).map(li=>{const cardText=li.innerText||'';const raw=clean(cardText);const lines=[...new Set(cardText.split(/\r?\n+/).map(clean).filter(Boolean))];const times=[...raw.matchAll(/\b(?:[01]?\d|2[0-3]):[0-5]\d(?:\s*[AP]M)?\b/gi)].map(m=>m[0]);const durations=[...raw.matchAll(/\b(?:\d+\s*(?:h|hr|hrs|hour|hours)(?:\s*\d+\s*(?:m|min|mins|minute|minutes))?|\d+\s*(?:m|min|mins|minute|minutes))\b/gi)].map(m=>m[0]);const currency='USD';const cur=currency.toUpperCase();const priceRe=new RegExp('(?:\\p{Sc}|'+cur+')\\s*[\\d,.]+|[\\d,.]+\\s*(?:\\p{Sc}|'+cur+')','iu');const price=(raw.match(priceRe)||[])[0]||null;const stops=(raw.match(/(nonstop|direct|\d+\s*stops?)/i)||[])[0]||null;const flightNumbers=[...raw.matchAll(/\b(?:[A-Z]{2}|[A-Z]\d|\d[A-Z])\s?\d{1,4}\b/g)].map(m=>m[0]);const label=clean(li.querySelector('[aria-label*="flight with" i]')?.getAttribute('aria-label')||li.getAttribute('aria-label')||'');const legLine=lines.find(l=>/(?:nonstop|\d+\s*stops?)/i.test(l))||'';const carrier=(label.match(/flights?\s+with\s+([^.]+?)\s*\./i)||[])[1]||clean(legLine.replace(/^(?:nonstop|\d+\s*stops?)/i,'').replace(/\d+\s*hr(?:\s*\d+\s*min)?|\d+\s*min/ig,''))||null;const airports=[...raw.matchAll(/\b[A-Z]{3}\b/g)].map(m=>m[0]).filter(x=>x!==cur);return{searchedDate:date,airline:carrier,flightNumbers:[...new Set(flightNumbers)],times:[...new Set(times)],departureTime:times[0]||null,arrivalTime:times[1]||null,duration:durations[0]||null,stops,price,airports:[...new Set(airports)],raw:raw.slice(0,2500),lines:lines.slice(0,40)}});const unique=[...new Map(cards.map(x=>[x.searchedDate+'|'+x.raw,x])).values()];return{url:location.href,isGoogleFlights:/(^|\.)google\.com$/i.test(u.hostname)&&u.pathname.startsWith('/travel/flights'),query:q,searchedDate:date,blocked,filterDialogVisible:[...document.querySelectorAll('div[role="dialog"]')].some(visible),resultCount:unique.length,flights:unique.slice(0,100),bodyExcerpt:body.slice(0,2200)}})()
  1. Stitch outputs from all searched dates. Deduplicate only identical visible card evidence on the same date; retain separate dates when schedule or price differs. Apply the caller's airline and cabin filters conservatively using visible card text. Preserve null for fields not rendered, and do not infer that an airline operates a route merely because it was selected in the filter dialog.

  2. If Google shows CAPTCHA, unusual traffic, consent, sign-in, or an empty dynamic results page, record the date as blocked or unresolved. Do not solve challenges, retain challenge URLs or tokens, or claim that no flights exist. Stop reusing that challenged session and report the affected dates.

Possible Friction Points

  • The direct search surface is https://www.google.com/travel/flights?q=...&curr={currency}&hl={locale}; the query text carries origin, destination, date, trip type, and cabin.
  • The observed results use li.pIav2d for flight cards. Google can duplicate or change card markup, so deduplicate by searched date plus bounded raw card text.
  • The visible airline filter is opened by a button whose text or accessible label begins with Airlines; its dialog contains a role="switch" for select-all state and airline checkboxes. Airline names are rendered in surrounding row text rather than guaranteed checkbox labels.
  • Google may initially show a View more flights control. Expand it once before extraction, but do not enter booking or checkout.
  • No stable URL parameter for the airline filter was established. Treat airline filtering as an optional rendered-UI step or a conservative local text filter.
  • Date navigation controls can be stateful and may not expose a reusable URL parameter. For {center-date} ± {offset}, construct direct URLs for each ISO date and preserve the searched date in every output row.
  • The price is matched by any currency symbol (\p{Sc}) or the caller's {currency} code, and that same code is the only three-letter token excluded from airports. A fixed symbol-and-code list silently returns price: null for every card under a currency outside it, and leaks that currency's code into airports as though it were an airport.
  • Prices, schedules, availability, operating carriers, and displayed results are time-dependent. They are current rendered evidence, not booking guarantees.
  • The carrier is read from the card's Nonstop flight with {airline}. accessible label, falling back to the leg line with the stop count and duration stripped off. Observed cards print that leg as one run-together string, Nonstop1 hr 45 minJetstar, with no separator — so the airline cannot be picked out as its own line, and \bnonstop\b does not match there either, since a word boundary needs a non-word character between Nonstop and 1.
  • Card text must be split before whitespace is collapsed. Collapsing first leaves one long line, and every per-line read then returns the whole card. A connection can print several carriers or an "Operated by" line, so treat airline as the first carrier line and check lines for the rest.
  • A card may show multiple times, airports, or flight numbers for connections. Preserve all visible values and only map the first two times to departure and arrival when the card clearly presents them in that order.
  • Consent, sign-in, CAPTCHA, unusual-traffic, and empty dynamic pages are blocked or unresolved states. Do not infer flight availability from the query or from filter labels.
  • Keep the session open and reuse the same browser connection for the direct navigations when the browserless agent supports it; this reduces startup overhead but does not bypass Google's anti-bot controls.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=google.com&task=search-google-flights