Find Buser Bus Tickets by Route and Date

Site buser.com.brTask find-bus-ticketsVersion v3Updated Sep 21, 2026Category travel

Search a Buser intercity route for departures on a date, optionally narrowing to a caller-supplied seat type or departure-time window. This skill was captured from a live agent session on buser.com.br 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.

Find Buser bus departures for a specified origin, destination, and date. Both the seat-type filter and the departure-time window are caller-supplied and default to no filter, so the unfiltered call returns every rendered departure.

Use Cases

Use when the caller provides Brazilian cities or route slugs and a travel date. The caller may additionally request a seat type such as leito or semi-leito, and a departure-time window such as overnight or morning departures. The route-results page can be reached directly without visiting the homepage or operating the date-picker UI.

Automation Flow

  1. Build the route URL with Buser's lowercase city/state slugs:

https://www.buser.com.br/onibus/{origin-city-slug}-{origin-state}/{destination-city-slug}-{destination-state}?ida={YYYY-MM-DD} 2. In one browser call, goto that URL with waitUntil: "domcontentloaded", allow the client-rendered results to settle briefly if necessary, and run this evaluate() extractor on the loaded page. Set seatTypePattern, windowStartHour, and windowEndHour according to the request; leave them null to return every departure:

(() => {
const seatTypePattern=null,windowStartHour=null,windowEndHour=null;
let seatRe=null;try{seatRe=seatTypePattern?new RegExp(seatTypePattern,'i'):null}catch{}
const hasWindow = Number.isInteger(windowStartHour) && Number.isInteger(windowEndHour);
const inWindow = h => windowStartHour <= windowEndHour
  ? h >= windowStartHour && h <= windowEndHour
  : h >= windowStartHour || h <= windowEndHour;
const visible = el => {
  const s = getComputedStyle(el);
  return s.display !== 'none' && s.visibility !== 'hidden' && el.getBoundingClientRect().width > 0;
};
const cards = new Map();
const roots = seatRe ? [...document.querySelectorAll('body *')] : [...document.querySelectorAll('article, li, [role="article"], [data-testid*="trip"], [data-testid*="offer"], [data-testid*="card"]')];
for (const el of roots) {
  if (!visible(el)) continue;
  if (seatRe && !seatRe.test((el.textContent || '').replace(/\s+/g, ' ').trim())) continue;
  const card = el.closest('article, li, [role="article"], [data-testid*="trip"], [data-testid*="offer"], [data-testid*="card"]') || el.parentElement;
  if (!card || !visible(card)) continue;
  const text = (card.textContent || '').replace(/\s+/g, ' ').trim();
  if (!text || text.length > 2500) continue;
  if (seatRe && !seatRe.test(text)) continue;
  const times = [...text.matchAll(/\b(?:[01]\d|2[0-3]):[0-5]\d\b/g)].map(m => m[0]);
  if (!times.length) continue;
  const href = card.querySelector('a[href]')?.href || null;
  const key = `${text}|${href || ''}`;
  cards.set(key, {text, href, times, inWindow: hasWindow ? inWindow(Number(times[0].slice(0, 2))) : null});
}
const all = [...cards.values()];
return {url: location.href, seatTypePattern, windowStartHour, windowEndHour, departures: hasWindow ? all.filter(x => x.inWindow) : all};
})()
  1. If the page uses a different rendered card ancestor, inspect only the current page and extend the ancestor selector; do not navigate through the homepage.

Possible Friction Points

  • The direct results route uses city/state slugs under /onibus/; the observed date query parameter that reaches the final state is ida={YYYY-MM-DD}. data_ida={YYYY-MM-DD} was also observed as an equivalent route parameter, but prefer ida.
  • Results are client-rendered after navigation, so extraction may need a short settle delay after domcontentloaded.
  • Worked example, overnight sleeper buses: seatTypePattern of \bleito(?:-cama)?\b matches both leito and leito-cama case-insensitively, and windowStartHour=18 with windowEndHour=5 selects departures from 18:00 through 05:59. The window wraps past midnight when the start hour is greater than the end hour.
  • windowStartHour/windowEndHour filter on the first clock time in the card, which is the departure time in the observed layout. Verify that ordering before trusting the filter if Buser changes its card markup.
  • Do not bake a seat type or time window into the extractor. The filters are caller inputs; the extractor returns the rendered card text and link rather than assuming a fragile single CSS class.
  • Neighborhoods or arrival areas such as Flamengo are not represented in the observed route URL; use the city route and report the rendered destination details when available.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=buser.com.br&task=find-bus-tickets