jackwener/OpenCLI · error · CommandExecutionError
Indeed served a Cloudflare challenge page
Error message
Indeed served a Cloudflare challenge page
What it means
Thrown when the Indeed search page is detected as a Cloudflare challenge page ('Just a moment' title or cf-* elements). The CLI detects and surfaces this instead of returning empty or broken results.
Source
Thrown at clis/indeed/search.js:98
jk,
title: b.querySelector('h2.jobTitle span')?.textContent?.trim() ?? '',
company: b.querySelector('[data-testid="company-name"]')?.textContent?.trim() ?? '',
location: b.querySelector('[data-testid="text-location"]')?.textContent?.trim() ?? '',
salary: b.querySelector('.salary-snippet-container span')?.textContent?.trim() ?? '',
tags,
});
}
const blockedHeadline = document.title || '';
const challenge = blockedHeadline.includes('Just a moment') || !!document.querySelector('[id^="cf-"]');
return { cards: out, challenge, ready };
})()`);
}
catch (e) {
throw new CommandExecutionError(`Failed to scrape Indeed search DOM: ${e?.message ?? e}`, 'The page may not have fully loaded; try again.');
}
if (cards?.challenge) {
throw new CommandExecutionError('Indeed served a Cloudflare challenge page', 'Open https://www.indeed.com in the connected browser and clear the challenge, then retry.');
}
if (!cards?.ready) {
throw new CommandExecutionError('Indeed search page did not expose result or empty-state markers within 15s', 'Indeed may still be loading or the DOM shape may have changed; retry after opening Indeed in the connected browser.');
}
const list = Array.isArray(cards?.cards) ? cards.cards : [];
if (list.length === 0) {
throw new EmptyResultError('indeed search', `No Indeed jobs matched "${query}"${location ? ` in ${location}` : ''}`);
}
return list.slice(0, limit).map((c, i) => searchCardToRow(c, start + i + 1));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Open https://www.indeed.com in the connected browser and clear the challenge, then retry
- Switch to a normal browser profile (non-headless) and a residential IP
- Disable VPN/proxy or change network
- Add delays between searches to reduce rate-based flagging
- Browse Indeed normally once to obtain clearance cookies before scraping
Defensive patterns
Strategy: retry
Validate before calling
const title = await page.title();
if (title.includes('Just a moment') || (await page.$('[id^="cf-"]'))) {
// clear the challenge manually in the connected browser first
} Try / catch
try {
const rows = await indeed.search({ query, location });
} catch (e) {
if (e.message.includes('Cloudflare challenge')) {
// pause, ask user to solve challenge in connected browser, then retry
}
throw e;
} Prevention
- Use residential IPs; avoid datacenter/VPN ranges
- Keep requests paced and human-like
- Use a persistent, non-headless browser profile
- Maintain Cloudflare clearance by browsing Indeed periodically
When it happens
Trigger: cards.challenge is true after evaluating the search page DOM.
Common situations: Flagged IP (VPN/datacenter/proxy); headless browser automation detected; burst of searches from one session; missing Cloudflare clearance cookies after cache clear.
Related errors
- Indeed served a Cloudflare challenge page
- Upwork served a Cloudflare challenge page
- FETCH_ERROR
- Booking.com served a verification / captcha page; retry late
- Failed to scrape Indeed job detail DOM: ${e?.message ?? e}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/fe63e94698d9a850.
Report an issue: GitHub.