{"record":{"id":"667ea21a8f43c080","repo":"jackwener/OpenCLI","slug":"trip-com-is-asking-for-a-verification-complete-it","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":"warning","filePath":"clis/trip/attraction.js","lineNumber":48,"sourceCode":"        { name: 'query', required: true, positional: true, help: 'Destination or attraction keyword (e.g. Tokyo / Paris / Louvre)' },\n        { name: 'limit', type: 'int', default: 20, help: 'Number of results (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'name',\n        'rating', 'reviews', 'booked',\n        'price', 'currency',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const query = parseKeyword('query', kwargs.query);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildAttractionSearchUrl(query);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_ATTRACTIONS_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 attraction', `No attractions for \"${query}\"`);\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Trip.com things-to-do page did not render product cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildAttractionExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Trip.com attraction DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Trip.com attraction cards rendered but parser did not find required detail-link anchors');\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            name: r.name,\n            rating: r.rating,","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/attraction.js#L30-L66","documentation":"The `trip attraction` command loads Trip.com's things-to-do search page in a cookie-backed browser session. The in-page wait script (WAIT_FOR_ATTRACTIONS_JS) reports state 'captcha' when Trip.com shows a bot-verification / challenge instead of product content, and the command then throws AuthRequiredError telling you to complete the verification in your browser session and retry. This is an intentional hard stop: scraping cannot proceed until a human passes the check.","triggerScenarios":"Calling the trip attraction CLI when page.evaluate(WAIT_FOR_ATTRACTIONS_JS) resolves to 'captcha' — Trip.com returned an anti-bot challenge for the attraction search URL (buildAttractionSearchUrl(query)) instead of the things-to-do page.","commonSituations":"Expired or stale Trip.com cookies in the shared browser profile; too many rapid automated requests triggering rate-limit challenges; datacenter/VPN IP flagged by Trip.com; headless browser fingerprint detected; first run of a session that has never been authenticated interactively.","solutions":["Open the same browser profile/session interactively, complete the Trip.com verification manually, then rerun the command.","Refresh the stored Trip.com cookies (log in again interactively) since the CLI uses Strategy.COOKIE.","Reduce request frequency / add delays between calls to avoid rate-limit challenges.","Switch off VPN/proxy or use a residential IP, as datacenter IPs commonly trigger Trip.com challenges."],"exampleFix":"// before: blind retry loop against Trip.com\nfor (let i = 0; i < 3; i++) { await runCli(['trip', 'attraction', query]); }\n// after: catch AuthRequiredError and pause for human verification\ntry {\n  await runCli(['trip', 'attraction', query]);\n} catch (e) {\n  if (e.name === 'AuthRequiredError') {\n    await openBrowserForManualVerification('trip.com'); // complete check, refresh cookies\n    await runCli(['trip', 'attraction', query]);\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  return await runCli(['trip', 'attraction', query]);\n} catch (e) {\n  if (e.name === 'AuthRequiredError') {\n    // cannot self-heal: require human to complete the Trip.com check\n    await promptManualVerification(e.message); // open browser session, solve challenge\n    return runCli(['trip', 'attraction', query]); // single retry, no loop\n  }\n  throw e;\n}","preventionTips":["Keep Trip.com cookies fresh by re-authenticating interactively before batch runs.","Throttle automated Trip.com requests well below rate-limit thresholds.","Avoid VPN/datacenter IPs that trip Trip.com's bot detection.","Never auto-retry AuthRequiredError in a loop — it needs human verification first."],"tags":["captcha","anti-bot","auth-required","scraping","trip-com"],"backgroundTag":"captcha-challenge-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}