Compare one-way and round-trip flight prices

Site united.comTask compare-one-way-round-trip-flight-pricesVersion v13Updated Sep 16, 2026Category travel

Compare United one-way and round-trip flight prices from direct result URLs, including multi-passenger searches, fare constraints, outbound selection, return-fare evidence, and itinerary totals. This skill was captured from a live agent session on united.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.

Use United direct choose-flights URLs to compare one-way and round-trip prices for any route, passenger count, dates, cabin, and optional fare constraints. Return visible fares, flight details, fare-label evidence, filter evidence, page state, return-fare evidence, and itinerary-total evidence.

Use Cases

  • Compare one-way and round-trip flight prices for a route.
  • Check adult, child, and other multi-passenger searches.
  • Test refundable, nonstop, Premium Plus, or Basic Economy-excluded fares.
  • Distinguish visible results from empty results, bot challenges, unavailable dates, or United errors.
  • Select an outbound and inspect return fares and itinerary totals.

Automation Flow

  1. Build the one-way URL: https://www.united.com/en/us/fsr/choose-flights?f={origin}&t={destination}&d={departure-date}&tt=0&sc=7&px={passengers}&taxng=1&clm={cabin}&st={sort}&tqp=R.
  2. Build the round-trip URL: https://www.united.com/en/us/fsr/choose-flights?f={origin}&t={destination}&d={departure-date}&r={return-date}&tt=1&sc=7%2C7&px={passengers}&taxng=1&clm={cabin}&st={sort}&tqp=R&newHP=True; if it errors, retry with sc=7 and omit newHP=True.
  3. Encode United's passenger vector carefully: the observed vector for two adults and one child is 2,0,0,0,0,1,0,0; map each passenger type to the site's vector position rather than assuming the child is the second value.
  4. For refundable fares with Basic Economy excluded, append ft=2&bef=0. mm=0 alone did not expose refundable labels. Treat Premium Plus and nonstop as requested constraints, but confirm them from visible card text because clm=7 can display Economy and Polaris options.
  5. In one BQL call, navigate directly, solve Akamai if presented, wait for a flight container or rendered error/empty/unavailable-date state, and run this evaluator. Scroll through the results once and rerun if cards are lazy-rendered; deduplicate cards before reporting first-page and later-page results.
(() => {
const clean=s=>String(s||'').replace(/\s+/g,' ').trim();
const visible=e=>{const r=e?.getBoundingClientRect(),s=e&&getComputedStyle(e);return !!e&&r.width>0&&r.height>0&&s.display!=='none'&&s.visibility!=='hidden'};
const body=clean(document.body?.innerText),priceRe=/(?:US\s*)?\$\s*[\d,]+(?:\.\d{2})?|[\d,]+(?:\.\d{2})?\s*(?:USD|US\$)/gi;
const amount=s=>{const m=String(s||'').replace(/,/g,'').match(/(?:\$|USD|US\$)\s*(\d+(?:\.\d{2})?)|(\d+(?:\.\d{2})?)\s*(?:USD|US\$)/i);return m?Number(m[1]||m[2]):null};
const botChallenge=/captcha|verify you are human|bot challenge|unusual traffic|access denied/i.test(body)||!!document.querySelector('iframe[src*="captcha"],[id*="captcha" i],[class*="captcha" i]');
const error=/unable to complete your request|we['’]re sorry|try again later|request.*(?:error|complete)|system error|technical difficulties/i.test(body);
const unavailable=/not available|outside.*(?:booking|schedule)|select a different date|date.*unavailable|currently unavailable/i.test(body)&&!error;
const empty=/no flights|no results|nothing found|empty/i.test(body)&&!error&&!unavailable;
const cards=[...document.querySelectorAll('div[class*="flightContainer"]')].filter(c=>visible(c)&&/Origin|Destination/i.test(c.innerText||''));
const flights=cards.map((card,index)=>{const text=clean(card.innerText),times=text.match(/\b(?:1[0-2]|[1-9]):[0-5]\d\s*(?:AM|PM)\b/gi)||[],prices=[...new Set((text.match(priceRe)||[]).map(clean))],nums=prices.map(amount).filter(Number.isFinite),labels=[...new Set([...card.querySelectorAll('button,[role="button"]')].map(e=>clean((e.innerText||'')+' '+(e.getAttribute('aria-label')||'')+' '+(e.getAttribute('aria-labelledby')||'')).replace(/\s+select to view fare options$/i,'')).filter(x=>/economy|premium plus|polaris|refundable|basic/i.test(x)))],stops=text.match(/\b(?:\d+ STOP|NONSTOP)\b/i)?.[0]||null;return{index,origin:text.match(/\b([A-Z]{3}) Origin\b/i)?.[1]||null,destination:text.match(/Destination[\s\S]*?\(([A-Z]{3})\)/i)?.[1]||null,depart:times[0]||null,arrive:times[1]||null,duration:text.match(/\b\d+H(?:,\s*\d+M)?\b/i)?.[0]||null,stops,flightNumbers:[...new Set(text.match(/\bUA\s*\d{2,4}\b/gi)||[])],fareLabels:labels,farePrices:prices,lowestDisplayedFare:nums.length?Math.min(...nums):null,isNonstop:/^NONSTOP$/i.test(stops||''),isPremiumEconomy:labels.some(x=>/premium plus|premium economy/i.test(x))||/premium economy|premium plus/i.test(text),isRefundable:/refundable|fully refundable|refundability/i.test(text)||labels.some(x=>/refundable/i.test(x)),hasBasicEconomy:/basic economy/i.test(text)||labels.some(x=>/basic/i.test(x)),soldOut:/sold out|not available|unavailable/i.test(text),text:text.slice(0,2000)}});
const allText=[...document.querySelectorAll('body *')].filter(visible).map(e=>clean(e.innerText)).filter(t=>t&&t.length<900);
const evidence=(re,n)=>[...new Set(allText.filter(t=>re.test(t)&&([...t.matchAll(priceRe)].length||/refundable|basic economy/i.test(t))).slice(0,n))];
const fares=flights.flatMap(f=>f.farePrices).map(amount).filter(Number.isFinite);
return{url:location.href,pageType:/choose-travelers|traveler/i.test(location.pathname)?'traveler-or-cart':'flight-results',searchState:botChallenge?'bot-challenge':error?'site-error':flights.length?'results':unavailable?'date-unavailable':empty?'empty':'unknown',botChallenge,totalCards:flights.length,lowestDisplayedFare:fares.length?Math.min(...fares):null,flights:flights.slice(0,50),filterEvidence:{refundable:/refundable|fully refundable/i.test(body),basicEconomyExcluded:/basic economy.*(?:excluded|omit|remove)|exclude.*basic economy/i.test(body)||/[?&]bef=0(?:&|$)/i.test(location.search),premiumEconomy:/premium economy|premium plus/i.test(body),nonstop:/nonstop|direct/i.test(body),queryParams:Object.fromEntries(new URL(location.href).searchParams)},returnFareEvidence:evidence(/return|round trip|select .*fare|economy|business|first/i,30),totalEvidence:evidence(/total due|trip total|itinerary total|price breakdown|total price|grand total/i,20),body:body.slice(0,1600)};
})()
  1. Treat refundable, Basic Economy exclusion, requested cabin, and nonstop constraints as confirmed only when matching visible card text or filter evidence exists. Fare labels may be rendered in button text rather than aria-label; inspect both.
  2. To inspect return pricing, select a visible outbound fare button inside its flight container, preferably using its fare text or button[aria-label^="Select "], wait, and rerun the evaluator. If navigation reaches choose-travelers, inspect the page body for return evidence and total evidence; United may show only the outbound under an ONEWAY label while still showing Total due. Report return fares unavailable when absent, but retain any displayed total.
  3. If the direct URL fails, use the homepage fallback; clear airport inputs through the native setter and dispatch input before typing, select autocomplete matches, and set the homepage cabin control when available. The observed homepage Premium economy option used select#cabinType value 1, but its equivalence to direct clm values is unverified.

Params

ParamWhat it doesExample value
originDeparture airport code mapped to fEWR
destinationArrival airport code mapped to tFRA
departure-dateDeparture date mapped to d in YYYY-MM-DD format2027-06-15
return-dateReturn date mapped to r2027-06-29
ttTrip type: 0 one-way, 1 round-trip1
passengersPassenger vector mapped to px; position is passenger-type-specific2,0,0,0,0,1,0,0
cabinDirect cabin/search option mapped to clm7
scSearch configuration7,7
taxngTax display/search option1
stResult sort modebestmatches
tqpObserved result modifierR
newHPOptional newer round-trip search modeTrue
mmOptional observed search modifier0
ftObserved refundable-fare filter state2
befObserved Basic Economy exclusion state0
verify-returnSelect an outbound and inspect return fares and totalstrue
nonstopRequested nonstop constraint; verify in card texttrue
premium-economyRequested Premium Economy constraint; verify visible cabin evidencetrue
refundableApply ft=2&bef=0 and verify visible refundable texttrue
include-basic-faresHomepage fallback controlfalse
origin-cityHomepage fallback autocomplete textNewark
destination-cityHomepage fallback autocomplete textFrankfurt
homepage-cabin-valueObserved homepage Premium economy select value1

Possible Friction Points

TriggerAction
Akamai challenge blocks or intermittently prevents resultsRestart the BQL session with a US residential proxy, solve Akamai, then revisit the direct URL.
Direct choose-flights URL shows a United request-completion errorCheck the passenger vector first; use the passenger-type mapping confirmed for the requested mix, retry in a fresh BQL session, then use the homepage fallback.
Requested departure date is outside United's currently bookable window or the homepage marks it unavailableReport date-unavailable, do not report fares or page-two cards, and retain the unavailable-date evidence.
px places a child in the wrong passenger positionUse the site's passenger-type vector; for two adults and one child, use 2,0,0,0,0,1,0,0, not 2,1,0,0,0,0,0,0.
mm=0 shows no refundable labelsApply the observed ft=2&bef=0 filter state and rerun extraction.
clm=7 shows Economy or Polaris alongside Premium PlusDo not call the search Premium-Plus-only; filter or classify cards using visible fare labels.
Fare labels are absent from aria-labelRead visible button text and aria-labelledby content; report that text as fare-label evidence.
Homepage calendar marks the requested date unavailableReport the date as unavailable and retain any separate direct-URL error state; do not invent fares.
Homepage airport input appends new textClear it with the native input setter and dispatch input before typing.
Homepage airport autocomplete returns no matching locationReplace the code with the full city name and select the matching suggestion.
United broadens an airport search to nearby airportsReport each returned airport and filter flights by the requested route.
Additional cards are below the initial viewportScroll through results, rerun the evaluator, and deduplicate by route and text.
Selecting an outbound reaches choose-travelers with ONEWAY and no return fare evidenceReport return fares unavailable, retain any visible Total due or itinerary-total evidence, and do not classify the original search as empty.
Later cart state shows Session expired or Your cart is emptyReport the original result evidence; mark return fares and totals unavailable only when no earlier total was captured.
Round-trip URL with sc=7%2C7&newHP=True behaves like the base flowRetry the base URL with sc=7, omit newHP=True, and use the returned page state.
Result page contains no visible price-like valuesWait for rendering and rerun once; if still empty, report fares as unavailable.
Date-picker fallback opens on the wrong monthMove the calendar with month controls until the requested date is visible, then select its accessible grid cell.
Homepage exposes Premium economy but direct results lack matching cabin textReport cabin mapping as unverified rather than treating the homepage option or clm value as confirmed.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=united.com&task=compare-one-way-round-trip-flight-prices