Skip to main content
You’ve sent a run, it came back COMPLETED, but the result is empty or wrong. Or maybe it outright FAILED. Before you start rewriting your goal, check whether the site is blocking you — bot detection is the most common cause of silent failures, and the fix is usually two lines of code. This guide walks through the full process: confirm the problem, apply the right configuration, and tune your goal to behave more like a human.
Examples use the Python SDK. The same parameters work across all SDKs and the REST API — see API Reference for TypeScript and cURL equivalents.

Installation

Set your API key as an environment variable so you don’t have to pass it explicitly:

Step 1: Confirm Anti-Bot Is the Problem

Don’t assume. Sites can fail for lots of reasons — slow JavaScript, unexpected layout changes, ambiguous goals. Anti-bot has specific fingerprints. Look for them first.

Get the streaming URL and watch the browser

Every run produces a streaming_url — a live browser preview you can open while the run is happening. This is the fastest way to see exactly what the agent encountered. Use agent.stream() to capture it as soon as it’s available:
The on_progress callback shows each step the agent took — if it got stuck on a challenge page, you’ll see it stop there. If you already started a run with agent.queue(), retrieve the streaming URL from the run object:

What to look for in the browser preview

Open streaming_url in your browser. What you see tells you what happened:
What you seeLikely cause
Cloudflare challenge / “Checking your browser”Cloudflare bot detection
DataDome popup or redirectDataDome protection
Blank page or infinite spinnerIP-based block or JS fingerprinting
CAPTCHA (reCAPTCHA, hCaptcha)CAPTCHA gate — cannot be solved automatically
”Access Denied” or 403 pageIP or User-Agent block
Login page when you expected contentSession-based bot detection

Check the result — COMPLETED doesn’t mean it worked

The result field is a better indicator of agentic success.
Anti-bot signatures in the result:
  • Fields are all null or empty arrays AND the streaming view shows the target content was never loaded
  • result.reason mentions “access denied”, “blocked”, or “could not find”
If the streaming view shows a challenge page and the result is empty or a failure — you’ve confirmed anti-bot. Move to Step 2.

Step 2: Enable Stealth Mode and Proxy

Apply both together. Stealth changes the browser fingerprint; the proxy changes the IP. Sites that use anti-bot services correlate both signals — changing only one often isn’t enough.

Switch to stealth browser

BrowserProfile.STEALTH is a modified browser with anti-detection techniques. The default (BrowserProfile.LITE) is faster but doesn’t include these measures.

Add a proxy

Choosing a country: Pick the country where the site’s primary users are. Available values:
EnumCountry
ProxyCountryCode.USUnited States
ProxyCountryCode.GBUnited Kingdom
ProxyCountryCode.CACanada
ProxyCountryCode.DEGermany
ProxyCountryCode.FRFrance
ProxyCountryCode.JPJapan
ProxyCountryCode.AUAustralia

Verify what proxy was actually used

After a run, browser_config on the run object confirms what was applied:

Full example with both applied

Watch the streaming view again after this change. If the actual page loads instead of a challenge screen — you’re through. Move to Step 3 to make the run more reliable at scale.
TinyFish cannot solve CAPTCHAs (reCAPTCHA, hCaptcha, etc.). The configurations above — stealth mode, proxies, and human-like goal patterns — reduce the likelihood of CAPTCHAs being triggered, but if a site serves one, it’s a hard limit for now. We’re actively working on expanding our anti-detection capabilities.

Step 3: Guide the Agent to Behave More Like a Human

Stealth and proxy get you past the door. But some sites layer behavioral analysis on top of fingerprinting — they watch for robotic patterns like instant form submissions, missing cookie consent dismissals, or zero mouse dwell time. Your goal controls a lot of this behavior. Bot detection systems often look at whether a user interacted with a consent banner before the main content. Always dismiss it explicitly:

Add deliberate pauses at suspicious checkpoints

Sites with aggressive behavioral detection (checkout pages, login flows) flag runs that move too fast:

Describe elements visually, not by selector

Automation-aware selectors are sometimes deliberately changed to trip scrapers. Visual descriptions are more resilient:

Use numbered steps for multi-step flows

For login flows or multi-page workflows, numbered steps give the agent explicit decision points rather than leaving it to guess:

Add explicit fallback instructions

Protected sites sometimes show intermediate pages (challenge passed, now redirecting). Tell the agent how to handle them:

Putting It All Together

A complete hardened run for a protected site:

Decision Tree


Creative Solutions and Iteration

When a site is actively defended, the most effective approach is often to rethink the workflow rather than force the original one. Watch yourself do it first. Before writing your goal, navigate to the target site yourself and think through what a human would actually do. Use that as your script. The streaming view is also useful here — watch a run or two to understand exactly what the agent encounters before committing to a final goal. Start at the front door. Linking directly to a filtered search results page or a deep URL can look robotic. Starting at target.com and navigating to your destination — searching for a product, clicking through a category — often succeeds where a direct deep link fails. Go to the source. If the formatted data you need lives behind anti-bot and paywalls, ask whether the underlying raw data is available elsewhere. Aggregator sites are often heavily protected; their primary sources may not be. Synthesizing from multiple simpler sources is frequently more reliable than fighting for one complex one. Check for a public API or feed first. Some sites that actively block scraping also publish APIs, RSS feeds, or sitemaps. Five minutes checking saves a lot of iteration. Keep dwell time low. The longer an agent stays on a site, the higher the likelihood of detection. Balancing human-like navigation with speed matters — break large workflows into focused, smaller tasks that can be handled by multiple agents running in parallel. You get both the human-like pacing and the throughput. Scale is one of TinyFish’s superpowers. Time your runs intentionally. Anti-bot systems are sensitive to traffic volume. Running during off-peak hours for your target site (for US-based sites, late morning to early afternoon PST often works well) can reduce the likelihood of triggering rate-based challenges. If you’re testing a new workflow, start with a single run during a quiet period before scaling up. Vary your entry points at scale. If you’re running hundreds of batch jobs against the same site, uniform traffic patterns can themselves become a fingerprint — even across different IPs. Mixing up how runs navigate to their destination (some via homepage search, some via category pages, some direct) makes the aggregate traffic look more organic. Runs have a 10-minute timeout, so this also naturally encourages breaking complex workflows into smaller, parallelizable pieces. Design goals to complete their core task well within that limit. Manage concurrency intentionally. TinyFish does not throttle runs by domain — if you enqueue a large batch against the same site, they will fire in parallel up to your account’s concurrency limit. For sensitive sites, consider staggering your jobs in your own queuing logic rather than enqueuing everything at once.

Authenticated Sessions

Logging in is one of the most effective anti-bot techniques. Logged-in users are treated very differently by most protection systems, so an authenticated session often sails past challenges that block anonymous traffic — and it unlocks gated content at the same time. Connect your password manager, then set use_vault: true on a run and TinyFish signs in with the credentials you select. See Vault Credentials for details.
Vault credentials are currently supported in the Playground, REST API, Python SDK, and TypeScript SDK. CLI support is coming soon — see Connect Your Vault for the latest.

What’s Coming

TinyFish continuously improves browser behavior and anti-detection performance across the web. If a site blocked you on a previous project, it’s worth trying again — the same run that failed before may work without any changes on your end. We’re also actively expanding our anti-detection capabilities.

Need Help?

If you’re stuck on a specific site, share the URL and your current configuration with us — we can often diagnose the issue quickly.