Find FlixBus departures for an origin, destination, and travel date, including departure and arrival times, duration when shown, and prices.
Use Cases
Use for route searches when the caller provides city names and a travel date but no FlixBus itinerary ID. The route landing page uses a non-obvious slug pattern: /bus-routes/bus-{origin-slug}-{destination-slug}.
Automation Flow
- Build the route URL directly by lowercasing each city name, replacing spaces and punctuation with hyphens, and removing duplicate hyphens:
https://global.flixbus.com/bus-routes/bus-{origin-slug}-{destination-slug}.
2. In one browser navigation, goto that URL with waitUntil: "domcontentloaded", then wait briefly for the route widget/results to render. If the requested date is not already selected, select {travel-date} in the page's booking widget before extraction.
3. If the consent dialog is present, dismiss it with button[data-testid='uc-ccpa-button'] before reading the page. Do not treat the consent dialog as a bus option.
4. Evaluate the following function on the loaded route/results page. It returns one object per visible itinerary-like card or text block containing both a time and a price:
(() => {
const visible = el => {
const s = getComputedStyle(el), r = el.getBoundingClientRect();
return s.display !== 'none' && s.visibility !== 'hidden' && r.width > 0 && r.height > 0;
};
const timeRe = /\b(?:[01]?\d|2[0-3]):[0-5]\d\b/g;
const priceRe = /\p{Sc}\s?\d+(?:[.,]\d{1,2})?|\d+(?:[.,]\d{1,2})?\s?\p{Sc}|\b[A-Z]{3}\s?\d+(?:[.,]\d{1,2})?\b|\b\d+(?:[.,]\d{1,2})?\s?[A-Z]{3}\b|\b\d+(?:[.,]\d{1,2})?\s?(?:zł|Kč|kr|Ft|lei|TL)/gu;
const clean = s => s.replace(/\s+/g, ' ').trim();
const seen = new Set(), options = [];
for (const node of document.querySelectorAll('body *')) {
if (!visible(node) || node.children.length > 8) continue;
const text = clean(node.innerText || '');
if (!text || text.length > 1200) continue;
const times = [...new Set(text.match(timeRe) || [])];
const prices = [...new Set((text.match(priceRe) || []).map(clean))];
if (!times.length || (!prices.length && times.length < 2)) continue;
const key = `${times.join('|')}|${prices.join('|')}|${text}`;
if (seen.has(key)) continue;
seen.add(key);
const link = node.closest('a') || node.querySelector('a[href]');
options.push({
text,
departureTime: times[0] || null,
arrivalTime: times[1] || null,
times,
prices,
href: link ? link.href : null
});
}
return {options};
})()- Return the extracted options associated with
{travel-date}. Preserve multiple prices when the page shows fare variants, and report an empty list if no itinerary-like block is visible rather than inventing results.
Possible Friction Points
- The route page URL is formed from city slugs rather than a search query or opaque route ID.
- A consent overlay may block the page; the observed dismissal control is
button[data-testid='uc-ccpa-button']. - The route landing page may initially show general route information rather than date-filtered departures; ensure
{travel-date}is selected in the booking widget before extraction. - The generic extractor keeps a block when it shows a departure and arrival time, or one time plus a price token, so unrelated route-page text stays out without a price being mandatory. Its DOM ancestry heuristic may need adjustment if FlixBus changes its card markup.
priceRematches any Unicode currency symbol, any three-letter code, or a local currency word on either side of a number, becauseglobal.flixbus.comprices in CHF, CZK, SEK, DKK, NOK, HUF, RON, TRY and BRL as well as EUR. A route priced in a currency the pattern misses still returns its departures withprices: []rather than an empty result that reads as "no buses".