Find flight results on Kayak for a supplied route, dates, passenger mix, cabin, sort order, and optional airline filter, returning comparable fares and itinerary details.
Use Cases
Use when the caller wants Kayak flight options with a price sort and/or airline selection, especially when comparing specific carriers (for example Scoot, Starlux, or China Airlines). The caller should provide airport codes, flight dates, passenger counts or child ages, and any desired cabin or airline restrictions.
Automation Flow
Construct Kayak's direct flight-results URL without visiting the homepage:
https://{kayak-domain}/flights/{origin}-{destination}/{outbound-date}/{return-date}/{adults}adults[/children-{child-age-1}-{child-age-2}-...]?sort={sort}&fs=cfc=1;cabin={cabin}[;airlines={airline-code-1},{airline-code-2}]{kayak-domain}is the Kayak edition host, for examplewww.kayak.sgorwww.kayak.com; the displayed currency follows the domain, so pick the edition whose currency the caller wants and report it. Use ISO dates (YYYY-MM-DD),price_afor ascending price,efor Economy,pfor Premium Economy,bfor Business, andffor First. Omitfswhen no cabin or other filter is requested. Child ages are joined with hyphens afterchildren-.Encode requested airline names using Kayak carrier codes. Known mappings include
TR= Scoot,JX= Starlux, andCI= China Airlines. For the direct filter form observed on Kayak, useairlines=TR,airlines=JX,CI, or another comma-separated code list. Kayak may also accept the expanded formairlines=-multiple_airlines,{code-1},{code-2}; preserve the leading-multiple_airlineswhen that form is required by the rendered filter state. Airline filtering is optional and defaults to unfiltered results.For Premium Economy searches use
cabin=p; retain the cabin label returned by each itinerary because Kayak can identify an itinerary asMixedwhen its legs do not share the same cabin.In one browser-agent operation, navigate to the constructed URL, wait until dynamic results or a blocking page appears, then run this
evaluate()extractor on the current page:
(() => {
const origin='{origin}', destination='{destination}', airlineNames=[/* caller's requested airline names, e.g. 'Scoot','Starlux' */];
const clean = s => (s || '').replace(/\s+/g, ' ').trim();
const body = document.body?.innerText || '';
const lines = body.split(/\n/).map(clean).filter(Boolean);
const pageText = location.href + '\n' + body;
const captcha = /sitecaptcha|verify you are human|captcha/i.test(pageText);
const status = lines.filter(s => /of \d+ flights|No matching|Loading|complete/i.test(s)).slice(0, 50);
if (captcha) return { url: location.href, title: document.title, captcha: true, status, flights: [] };
const blocks = [];
let current = [];
for (const line of lines) {
if (/^Select$/i.test(line) && current.length) {
blocks.push(current);
current = [];
} else {
current.push(line);
}
}
if (current.length) blocks.push(current);
const flights = blocks.map(block => {
const joined = block.join(' | ');
const priceRe = /(?:[\p{Sc}]|[A-Z]{0,2}\$|\b(?:USD|EUR|GBP|SGD|AUD|JPY|INR|CAD|HKD)\b)\s*[\d,]+(?:\.\d{2})?/giu;
const prices = [...joined.matchAll(priceRe)].map(m => clean(m[0]));
const total = joined.match(/(?:[\p{Sc}]|[A-Z]{0,2}\$|\b(?:USD|EUR|GBP|SGD|AUD|JPY|INR|CAD|HKD)\b)\s*[\d,]+(?:\.\d{2})?\s*total/iu);
const wantAirlines = airlineNames.length ? new RegExp(airlineNames.map(a=>a.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')).join('|'),'i') : null;
const carriers = wantAirlines ? block.filter(s => wantAirlines.test(s)).slice(0, 6) : [];
const times = block.filter(s => /\b\d{1,2}:\d{2}\s*(?:AM|PM)?\s*[–-]/i.test(s)).slice(0, 6);
const routeCodes = new RegExp('stop|Direct|self-transfer|layover|\\b'+[origin,destination].filter(Boolean).join('\\b|\\b')+'\\b','i');
const routeOrStops = block.filter(s => routeCodes.test(s)).slice(0, 10);
const cabin = [...new Set(block.filter(s => /Economy|Premium Economy|Business|First|Mixed/i.test(s)))].slice(0, 4);
return {
pricePerPerson: prices[0] || null,
totalPrice: total ? clean(total[0]) : null,
carriers,
times,
routeOrStops,
cabin,
text: block.filter(s => s.length > 2 && !/^Go to/i.test(s)).slice(0, 30).join(' || ')
};
}).filter(f => f.pricePerPerson || f.totalPrice || f.carriers.length || f.times.length || f.routeOrStops.length);
return { url: location.href, title: document.title, captcha: false, status, flights };
})()- If Kayak redirects to
/sitecaptcha.html?out=...or the extractor reportscaptcha: true, report the anti-bot block and preserve the requested results URL from theoutparameter; never invent flight results. Otherwise return the extracted flights in the page's displayed currency and wording.
Possible Friction Points
- Kayak exposes route, dates, passenger counts, and child ages in the path rather than requiring form submission; child ages use a hyphen-separated
children-{age}segment. - The cheapest-first modifier is
sort=price_a; cabin filtering uses the semicolon-separatedfs=cfc=1;cabin={code}parameter. - On an unfiltered search (no requested airlines),
carriersis returned empty by design; read the operating carrier from each card's visibletextinstead of expecting a filledcarriersarray. - Airline filters are nested inside the same
fsparameter. Kayak has shown both the compact formairlines=TRorairlines=JX,CIand the expanded formairlines=-multiple_airlines,{codes}. Verify carrier labels in returned cards rather than assuming the filter syntax was honored. - Known carrier codes are
TRfor Scoot,JXfor Starlux, andCIfor China Airlines. - Results populate asynchronously after navigation. Wait for flight cards, price text, a flight-count/status line, or a captcha page before evaluating; a roughly 14-second wait may be needed for dynamic results.
- Result cards do not guarantee a stable public data attribute. The extractor segments rendered text around
Select, so missing fields must be treated as unavailable rather than inferred. - Kayak may display both per-person and total prices. Preserve both when available and compare fares using the displayed total when present.
- A Premium Economy filter may still produce a
Mixedcabin label for itineraries whose outbound and return legs differ; report the displayed label instead of normalizing it to Premium Economy.