{"record":{"id":"f1d501fde7184ca7","repo":"jackwener/OpenCLI","slug":"trip-com-is-asking-for-a-verification-complete-it-f1d501","errorCode":null,"errorMessage":"Trip.com is asking for a verification; complete it in your browser session and retry","messagePattern":"Trip\\.com is asking for a verification; complete it in your browser session and retry","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/trip/transfer.js","lineNumber":53,"sourceCode":"        { name: 'limit', type: 'int', default: 20, help: 'Number of vehicles (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'type',\n        'passengers', 'luggage',\n        'price', 'currency',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const city = parseKeyword('city', kwargs.city);\n        const airport = parseIataCode('airport', kwargs.airport);\n        const limit = parseListLimit(kwargs.limit);\n\n        const listUrl = buildTransferListUrl(city, airport);\n        await page.goto(listUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_TRANSFERS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('trip.com', 'Trip.com is asking for a verification; complete it in your browser session and retry');\n        }\n        if (waitResult === 'empty') {\n            throw new EmptyResultError('trip transfer', `No airport transfers for ${city} (${airport})`);\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Trip.com transfer listing did not render (state=${String(waitResult)}); check the city and airport code`);\n        }\n        const landedPath = await page.evaluate('location.pathname');\n        if (!/\\/airport-transfers\\/[^/]+\\/airport-[^/]+/i.test(String(landedPath))) {\n            throw new CommandExecutionError(`Trip.com bounced ${city} / ${airport} to the transfer landing; check the city name matches the airport IATA code`);\n        }\n        const raw = await page.evaluate(buildTransferExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Trip.com transfer DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Trip.com transfer cards rendered but parser did not find required price anchors');\n        }","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/transfer.js#L35-L71","documentation":"AuthRequiredError thrown when Trip.com's anti-bot layer intercepts the airport-transfer page and the wait probe reports 'captcha'. The library cannot proceed programmatically; Trip.com wants human verification tied to your browser session.","triggerScenarios":"Rapid repeated transfer queries from the same profile, running from a datacenter IP or headless browser fingerprint that Trip.com flags, or a shared browser session that already accumulated a challenge.","commonSituations":"Batch scripting many city/airport pairs in a loop; CI runners on cloud IPs; reusing an old browser profile with stale cookies; scraping during high-risk hours when Trip.com tightens bot checks.","solutions":["Complete the captcha manually in the browser session the library reuses, then retry","Slow down: add delays between requests and reduce query volume","Run from a residential IP / your normal machine instead of a datacenter","Use a warmed-up, persistent browser profile with real cookies","Switch to Trip.com's official API if this becomes routine"],"exampleFix":"// before\nfor (const ap of airports) await getTransfers(ap); // rapid loop -> captcha\n// after\nfor (const ap of airports) {\n  await getTransfers(ap);\n  await sleep(3000 + Math.random() * 2000);\n}","handlingStrategy":"retry","validationCode":"// throttle before calling\nlet lastCall = 0;\nasync function throttledGetTransfers(args) {\n  const wait = Math.max(0, 3000 - (Date.now() - lastCall));\n  await new Promise(r => setTimeout(r, wait));\n  lastCall = Date.now();\n  return getTransfers(args);\n}","typeGuard":"null","tryCatchPattern":"try {\n  const rows = await getTransfers(args);\n} catch (e) {\n  if (e instanceof AuthRequiredError) {\n    console.error('Open the shared browser session, solve the captcha, then rerun');\n    process.exitCode = 2; // distinct code for auth-required\n    return;\n  }\n  throw e;\n}","preventionTips":["Add randomized delays between Trip.com requests","Use a persistent, warmed-up browser profile","Avoid datacenter IPs for scraping","Stop batch runs early when a captcha appears instead of hammering"],"tags":["captcha","anti-bot","auth-required","scraping"],"backgroundTag":"captcha-challenge","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}