{"record":{"id":"005c0296e2fdeff6","repo":"jackwener/OpenCLI","slug":"trip-com-is-asking-for-a-verification-complete-it-005c02","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/hotel-search.js","lineNumber":55,"sourceCode":"        'name', 'score', 'reviewLabel', 'reviews',\n        'location', 'room',\n        'price', 'currency',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const cityId = parseCityId('city', kwargs.city);\n        const checkin = parseIsoDate('checkin', kwargs.checkin);\n        const checkout = parseIsoDate('checkout', kwargs.checkout);\n        if (checkin >= checkout) {\n            throw new ArgumentError(`--checkin must be before --checkout (got ${checkin} .. ${checkout})`);\n        }\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildHotelSearchUrl(cityId, checkin, checkout);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_HOTELS_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 !== 'content') {\n            throw new CommandExecutionError(`Trip.com hotel page did not render hotel cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildHotelExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Trip.com hotel DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new EmptyResultError('trip hotel-search', `No hotels for city ${cityId} on ${checkin} .. ${checkout}`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            name: r.name,\n            score: r.score,\n            reviewLabel: r.reviewLabel,\n            reviews: r.reviews,\n            location: r.location,","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/hotel-search.js#L37-L73","documentation":"This AuthRequiredError from clis/trip/hotel-search.js is thrown when WAIT_FOR_HOTELS_JS returns 'captcha' after navigating to the hotel search URL, meaning Trip.com served a verification challenge instead of hotel cards. Like the flight equivalent, it tells the caller that the shared browser session needs human verification before scraping can continue. Immediate blind retries typically just trigger the challenge again.","triggerScenarios":"page.evaluate(WAIT_FOR_HOTELS_JS) after page.goto(buildHotelSearchUrl(...)) returns exactly 'captcha'.","commonSituations":"Bursts of hotel searches from the same session/IP; fresh headless browser profiles without cookies; VPN or datacenter IPs flagged by Trip.com; aggressive automated scheduling hitting the site repeatedly.","solutions":["Complete the CAPTCHA manually in the same browser session, then rerun the command.","Throttle searches and add randomized delays between runs.","Switch to a residential IP and disable VPN/proxy for the session.","Use a persistent, cookie-warmed browser profile instead of ephemeral contexts."],"exampleFix":"// before\nawait runTripHotelSearch(args); // throws AuthRequiredError on captcha\n// after\ntry {\n  await runTripHotelSearch(args);\n} catch (e) {\n  if (e.name === 'AuthRequiredError') {\n    await pauseForManualCaptcha(page);\n    await runTripHotelSearch(args);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// Server-side captcha cannot be pre-checked; pace calls instead:\nawait sleep(3000 + Math.random() * 5000); // jittered spacing between hotel searches","typeGuard":"const isAuthRequired = (e) => e?.name === 'AuthRequiredError' || e instanceof AuthRequiredError;","tryCatchPattern":"try {\n  await runTripHotelSearch(args);\n} catch (e) {\n  if (isAuthRequired(e)) {\n    await waitForManualCaptchaResolution(page);\n    return runTripHotelSearch(args); // single retry post-verification\n  }\n  throw e;\n}","preventionTips":["Rate-limit hotel searches; they are captcha-prone when bursty.","Reuse warm browser profiles with Trip.com cookies.","Scrape from residential IPs.","Treat AuthRequiredError as a pause signal, not an auto-retry loop."],"tags":["captcha","anti-bot","auth-required","trip-com","hotels"],"backgroundTag":"captcha-challenge","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}