Today we're continuing our adventures in the wondrous world of scraping and taking a look at how to bypass the PerimeterX anti-bot system using a few potential solutions. It's not the easiest task, but I'll try to explain what to watch out for and will cover some key details to keep in mind.
So, let's get started!

What is PerimeterX?
I'm not sure about you, but to me the name "PerimeterX" sounds like it belongs to a secret military project or some evil AI. You could imagine it being announced by an overly dramatic voice-over and accompanied by "Ride of the Valkyries." Jokes aside, PerimeterX (also known as "HUMAN" — kinda ironic, eh?) is a bot protection system used by some websites to detect and block automated traffic, including your scraping tools. You'll mostly find PerimeterX on large high-traffic sites like e-commerce, ticketing, login forms and any place where bots cause (financial) damage.
In theory, it can catch anything from basic scrapers to more advanced headless browsers pretending to be regular users. And it keeps evolving — staying one step ahead of scrapers that are also getting smarter. Overkill? Maybe not, considering recent studies reveal that nearly half of all internet traffic comes from bots. Talk about dead Internet theory...
It works through both frontend scripts and backend checks, combining browser behavior with network-level data. So yeah, a site protected by PerimeterX/HUMAN is a tough nut to crack — this isn't your father's noscript
check or some entry-level honeypot. When surfing the net, you might've seen that annoying "Press & Hold to confirm you are human" button while browsing. That's the HUMAN challenge in all its beauty — shown when the system thinks your request is fishy. According to their docs, it's a "simple, no-hassle challenge" — but not to my fellow scraping enthusiast.
While PerimeterX doesn't publicly reveal all its inner workings, we can still look at some of the key signals it uses to tell humans apart from bots.
Learn how to scrape the web without getting blocked in our blog.
How PerimeterX detects bots
Before we dive into bypassing PerimeterX (or "HUMAN", if you prefer the new name), it's worth understanding how it actually works. Disclaimer: some of this might get a bit technical — PerimeterX doesn't rely on a single trick, but a whole toolbox of detection methods.
PerimeterX acts like a gatekeeper. It checks a bunch of markers to figure out if you're a real person or just another bot. It gathers data from your browser, network, and how you behave on the page — then digests all of that into a trust score. Based on that score, you're either allowed in like a normal user or hit with a challenge page. Obviously, when scraping the goal is to stay under the radar and avoid triggering those checks. No one enjoys surprise CAPTCHAs and extra challenges, which we'll show you how to avoid.
IP filtering
Let's start with one of the oldest tricks in the book: checking your IP address. PerimeterX looks at where the request comes from — not just the country or city, but also what kind of IP it is and it uses that info to decide if you look like a bot.
Quick refresher in case IPs sound confusing: your IP address is like a label your device (or bot, or proxy) wears when it goes online. It tells websites where to send information back — but it can also be used to judge who you are. If your IP looks like bot traffic, PerimeterX is going to be suspicious.
Not all IPs are treated the same:
- Residential IPs come from real homes. These usually look safe to PerimeterX.
- Mobile IPs are from mobile networks. They're also seen as "human", and because lots of people share them, they're harder to track.
- Datacenter IPs come from big server farms like AWS or Google Cloud. These are fast and cheap — but way too common for bots, so they're usually flagged.
- VPNs and public proxies also often get blocked, especially the well-known or free ones that show up on blocklists.
PerimeterX uses huge internal lists (and probably outside data too, but we'll never know) to give each IP a reputation score. If your IP has been used for scraping, spamming, or other automated stuff before, that score drops. Even a "clean" IP can go bad fast if you send too many requests too quickly.
How to deal with IP filtering
To avoid getting blocked just because of your IP, most scrapers stick to a few simple tricks:
- Rotate your IPs often so you're not sending too much traffic from the same one.
- Use residential or mobile proxies instead of datacenter ones. Yeah, they cost more — but they're way less likely to get flagged.
- Slow down your requests. If you send 50 requests per second, you're basically asking to get blocked.
- Mix up the locations — don't make it look like all your traffic is coming from the same place over and over.
Also, try not to keep using the same IP with the same fingerprint. Even a good IP can get burned if it acts too much like a bot.
Browser Fingerprinting
IP checks are just the first layer — PerimeterX goes deeper by looking at how your browser or tool looks and acts. This part is called fingerprinting.
Browser Fingerprinting means collecting small details about your setup to build a unique "digital ID." It's kind of like checking someone's clothes, voice, and handwriting at the same time. One thing alone might not tell much, but together they make a pretty clear picture. You'd be surprised how much info your browser gives away — your language, screen size, browser version, and a bunch of other stuff can all help websites figure out who (or what) you are. That's basically how tracking works, but that's a story for another day.
PerimeterX uses a mix of markers: your browser type, screen resolution, fonts you have, graphics card, language, and even how your JavaScript engine behaves when it runs weird code. Some things are really subtle, like how your device draws canvas images or handles edge-case functions — but it all adds up. They also look at TLS fingerprinting — that's how your browser sets up a secure connection (HTTPS). Different tools (browsers, bots, scraping libraries) use different settings under the hood. That process called the "TLS handshake" leaves a trace. If your client does it in a weird way, it sticks out.
Same with JavaScript: since the site can run code in your browser, it watches how your setup reacts. If things are missing, fake, or just behave strangely — that's a big red flag.
How to deal with fingerprinting
Making a fake fingerprint that actually looks real is super hard. Most tools that try to fake stuff like screen size or WebGL just end up looking wrong in a different way — which gets you caught anyway. What's the best solution? Honestly, just use a real browser.
Tools like Playwright, Puppeteer, or Selenium launch full browsers with most of the normal behavior already built in. You still need to tweak some things (like headless mode or automation flags), but it's a much better starting point. Some people use a hybrid trick: they visit the site with a real browser first (to build trust), then switch to a faster HTTP client for the actual scraping. That way you get stealth early on, and speed later. You can also use a stealth headless browser.
HTTP header checks
Another trick PerimeterX uses is checking your HTTP headers — the small bits of info sent with every request. They might seem boring and somewhat irrelevant, but to a bot detection system, headers are your handshake, your vibe check, and your browser's passport all at once.
Thing is, when your browser visits a website, it sends extra details along with the request — things like what browser you're using (User-Agent
), where you came from (Referer
), your preferred language, and what kind of content you can handle. These are called HTTP headers. This info helps websites show pages correctly — but it also helps them spot bots.
Real browsers send headers in a specific format, with certain fields, and even in a specific order. Yeah, it sounds weird, but header order actually matters. PerimeterX can flag requests that have missing headers, extra ones, or just the wrong order. Here's the problem: most scraping tools — like Python's requests
or Node's fetch
— don't copy browser headers very well. They send simple defaults, miss fields, or put them in the wrong order. And some libraries don't even let you control the order unless you dig deep.
PerimeterX might also check your HTTP version. Most browsers today use HTTP/2, while some scraping tools still use HTTP/1.1 by default. If your request shows up using an outdated version, that can also look suspicious.
How to deal with HTTP header checks
To avoid getting flagged, your scraper should look like it's coming from a real browser. That means:
- Send a full and realistic set of headers, not just a fake
User-Agent
. - Match the header order real browsers use (this might need a more advanced library).
- Don't leave out or mess up important values — like
Referer
,Origin
, orAccept
. - Use a library or setup that supports HTTP/2, and double-check that it's actually enabled.
Tip: open your browser's DevTools, go to the Network tab, and check what headers your browser sends when visiting the site. You can copy those and use them in your script.
Bonus: browser automation tools like Playwright or Puppeteer handle this for you. Since they launch real browsers, you get proper headers, the right HTTP version, and fewer things to worry about.
Behavioral analysis and CAPTCHAs
Even if you've got your headers, IP, and fingerprint looking perfect, PerimeterX still isn't done. One of its final defenses is watching what you actually do once you're on the site. Creepy? Yeah. But this approach works and it's called behavioral analysis. The idea is to check whether your actions feel like something a human would do. Think of it like a bouncer — they already let you in, but now they're watching how you act. Behave like a bot? You're out.
PerimeterX looks at stuff like:
- What pages you visit — and in what order
- How fast you move through the site
- If you load all the usual stuff like images, styles, and scripts
- Mouse movement, scrolling, clicking, and how long you pause
- How long you stay on pages or the whole site
- Timing — like clicking through 20 products in 2 seconds (yeah, no human does that)
Bots usually go too fast, skip loading page parts, and follow a very clean, robotic path. Real users take their time, scroll around, click randomly, get distracted, and act... unpredictable.
How to deal with behavioral analysis
Pretending to be a human is tough, but not impossible. Here's how bots can blend in better:
- Use browser automation to scroll, move the mouse, hover, click, and add random delays.
- Change things up: rotate your IP, browser version, screen size, OS, timezone, and other details.
- Load the full page, including images and scripts — don't just grab the raw HTML.
- Add some idle time between actions. Humans don't instantly click the next link — they wait, read, or get distracted.
- Avoid being too regular — don't always click the same button after the same delay.
- If you hit the HUMAN Challenge, you'll need to solve it manually or use a solver — if that's allowed in your use case.
How to bypass PerimeterX (HUMAN)
Now that we've seen how PerimeterX catches bots, let's talk about how to get past it. There's no magic button to turn it off, but some tools can make your life way easier.
Use a scraping API
One of the simplest ways to deal with PerimeterX is to not deal with it at all — and let someone else do the hard part. With ScrapingBee, you just send a request to our API, and we handle everything behind the scenes. That means headers, proxy rotation, fingerprint stuff, and even full browser rendering if needed. What you get back is clean HTML or structured JSON (depending on your preference) — no CAPTCHAs, no weird redirects, no headaches.
It works whether you're scraping a single page or running a big project. The setup is easy and it scales without much effort.
Registering at ScrapingBee
To try it out, go to ScrapingBee and sign up for a free trial. You'll get 1000 credits to test it — no credit card required. Once you're in, grab your API key from the dashboard.
You can also use the HTML Request Builder to test your requests right in the browser.
Using ScrapingBee with Python
We've also got an official Python client to make things even easier. Install it:
pip install scrapingbee
And use it like this:
from scrapingbee import ScrapingBeeClient
client = ScrapingBeeClient(api_key='YOUR_API_KEY')
response = client.get(
'https://zillow.com',
params={
'premium_proxy': True,
'country_code': 'fr'
}
)
response.text
For sites protected by PerimeterX, you'll want to turn on the premium proxy option. These proxies are harder to block and work better on sites with strong anti-bot systems.
If that's still not enough, you can also try our stealth proxy feature. It's made for really tough websites and helps you avoid detection even when other proxies fail.
Once you get the response, you can pass the HTML to something like BeautifulSoup and extract the data — no need to mess with browser automation.
Zillow scraper using ScrapingBee and BeautifulSoup
This script uses ScrapingBee to scrape Zillow's for-sale listings page and parses the results with BeautifulSoup.
from scrapingbee import ScrapingBeeClient
from bs4 import BeautifulSoup
client = ScrapingBeeClient(api_key='YOUR_API_KEY')
response = client.get(
'https://www.zillow.com/homes/for_sale/',
params={
'premium_proxy': True,
'render_js': True,
'screenshot': True,
'country_code': 'fr'
}
)
soup = BeautifulSoup(response.text, 'html.parser')
# Extract total result count
results_box = soup.select_one('#grid-search-results .result-count')
if results_box:
total_results = results_box.text.strip()
print(f"Total results: {total_results}")
else:
print("Could not find result count.")
# Extract first few listings
cards = soup.find_all(attrs={'data-test': 'property-card'})
print("\nFirst five listings:")
for card in cards[:5]:
price_tag = card.find(attrs={'data-test': 'property-card-price'})
price = price_tag.text.strip() if price_tag else 'N/A'
link_tag = card.find(attrs={'data-test': 'property-card-link'})
link = link_tag['href'] if link_tag and link_tag.has_attr('href') else 'N/A'
print(f"- {price} — {link}")
If you don't have BeautifulSoup on your PC, install it with:
pip install bs4
So, this script:
Connects to ScrapingBee using your API key and requests the Zillow for-sale page.
premium_proxy
: Uses high-trust proxies that are less likely to get blocked.render_js
: Tells ScrapingBee to render JavaScript on the page (Zillow requires this).screenshot
: Requests a screenshot of the page (optional).country_code
: Forces proxy location (in this case, France).
Parses the HTML returned in
response.text
using BeautifulSoup.Finds the total number of listings:
- Looks for an element with class
.result-count
inside the container with ID#grid-search-results
. - This typically contains text like
1,243 Homes
.
- Looks for an element with class
Extracts individual listing cards:
- Finds all elements with
data-test="property-card"
— each one is a single home listing.
- Finds all elements with
From each card, it pulls:
- The price from a
span
withdata-test="property-card-price"
(e.g.$79,900
). - The link from an
a
tag withdata-test="property-card-link"
(usually nested somewhere in the card).
- The price from a
The script prints:
- The total number of listings found.
- The price and link for the first five homes on the page.
Use a stealthy headless browser
If you're building your own scraping setup and want full control — but still need to get past PerimeterX — using a stealth browser is one of the best options. That's where Camoufox comes in.
Camoufox is a custom version of Firefox made for serious scraping. It's built to act like a real user — down to the smallest details — without using weird JavaScript tricks that can break or get you flagged. Think of it as Playwright or Puppeteer's sneaky cousin that knows how to stay invisible.
Here's what it does out of the box:
- Hides all the usual fingerprint clues (browser, OS, screen size, timezone, fonts, WebGL, and more)
- Changes fingerprints every session so it doesn't look like the same bot over and over
- Simulates human-like mouse movement and turns off distracting stuff like CSS animations
- Works with Playwright-style scripts
- Uses less memory and runs faster than many other tools
Camoufox is one of the best tools out there if you want to look like a normal user on sites that use PerimeterX.
Learn how to use Camoufox in our tutorial.
Getting started
First, install Camoufox with the optional geoip
support (recommended if you're using proxies):
pip install camoufox[geoip]
Next, download the actual browser:
camoufox fetch
Then you can use it in your script just like you would with Playwright:
from camoufox.sync_api import Camoufox
with Camoufox() as browser:
page = browser.new_page()
page.goto("https://example.com")
You can also customize the fingerprint to match a specific OS or pick randomly from a list:
with Camoufox(os=["windows", "macos", "linux"]) as browser:
# ...
That's it — Camoufox handles the rest. It rotates identities, stays current with the latest Firefox updates and quietly avoids detection while your scraper does its job.
Zillow scraper using Camoufox + BeautifulSoup
This version uses Camoufox, a stealthy headless browser based on Firefox, to open the Zillow listings page just like a real user. It then uses BeautifulSoup to parse the HTML and extract data.
from camoufox.sync_api import Camoufox
from bs4 import BeautifulSoup
import time
# ScrapingBee proxy credentials
SB_USER = "YOUR_SCRAPING_BEE_TOKEN"
SB_PARAMS = "render_js=true&premium_proxy=true" # can add more params
SB_PROXY = {
"server": "https://proxy.scrapingbee.com:8887",
"username": SB_USER,
"password": SB_PARAMS,
}
with Camoufox(geoip=True, os=["windows", "macos", "linux"], proxy=SB_PROXY) as browser:
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
timezone_id="America/New_York",
)
page = context.new_page()
# Zillow search URL for New York
zillow_url = (
"https://www.zillow.com/new-york-ny/"
)
page.goto(zillow_url, wait_until="networkidle")
page.wait_for_timeout(4000) # extra buffer
# light human‑like scroll
for _ in range(2):
page.mouse.wheel(0, 600)
time.sleep(1)
soup = BeautifulSoup(page.content(), "html.parser")
# total results
count = soup.select_one("#grid-search-results .result-count")
print("Total results:", count.text.strip() if count else "N/A")
# first five listings
cards = soup.find_all(attrs={"data-test": "property-card"})
print("\nFirst five listings:")
for card in cards[:5]:
price = card.find(attrs={"data-test": "property-card-price"})
link = card.find(attrs={"data-test": "property-card-link"})
print(f"- {price.text.strip() if price else 'N/A'} — {link['href'] if link else 'N/A'}")
What it does:
Launches Camoufox:
- Starts a stealth Firefox instance that mimics real users.
- In this example we also use ScrapingBee premium proxy but you can simply remove the
proxy=SB_PROXY
part or use your own proxy instead. - Uses
page.goto(...)
to open the Zillow page.
Waits for JavaScript content to load:
page.wait_for_timeout(5000)
pauses the script for 5 seconds.- This gives Zillow time to render dynamic content (like listings).
Gets the full page HTML:
page.content()
returns the rendered HTML.- Passed into BeautifulSoup for parsing.
Extracts the total number of listings:
- Looks for an element with class
result-count
inside#grid-search-results
.
- Looks for an element with class
Finds individual home listings:
- Selects elements with
data-test="property-card"
— these are the listing containers.
- Selects elements with
From each card, it grabs:
- The price, from a
span
withdata-test="property-card-price"
. - The link, from an
a
tag withdata-test="property-card-link"
(if present).
- The price, from a
Other stealth browser tools
Camoufox is a solid choice, but it's not the only tool out there. If you're using a different setup or just want other options, here are a couple more stealth tools to check out:
undetected-chromedriver (aka "ucd") is a tweaked version of Selenium's ChromeDriver that hides most of the usual signs of automation. It fixes
navigator.webdriver
, adjusts internal values, and acts enough like a real browser to fool many bot checkers. It works well with existing Selenium code, but it's tied to Chrome and can feel a bit heavier than newer tools. Learn more in our undetected-chromedriver tutorial.If you're using Playwright, you can add a stealth plugin that was first made for Puppeteer. It helps patch common fingerprinting leaks and smooths out automation behavior. It's not as deep as Camoufox when it comes to spoofing, but it's light, simple, and good enough for a lot of sites — especially if you combine it with decent proxies and realistic scraping logic. Learn more in our Playwright Stealth tutorial.
Reverse engineer it yourself
If you like digging into the technical stuff and have the time (and patience), you can try reverse engineering PerimeterX yourself. It's definitely not the easiest path — but it gives you full control over how your scraper works.
In short, this means figuring out what PerimeterX scripts do in the browser: what data they collect, how they calculate the trust score, and what triggers the HUMAN Challenge. Most of this happens in obfuscated JavaScript on the client side, so you'll need to read messy code, track network requests and follow how the scripts run.
Here are some tips if you want to explore this route:
- Use browser DevTools to inspect scripts and watch what they're doing
- Look for strange or delayed network requests — big blobs of data usually mean behavioral info being sent to their servers
- Check cookies, local storage, and session storage — some values might relate to risk scores or challenges
- Compare how a normal browser behaves vs a bot setup — and spot the differences
You probably won't be able to copy everything PerimeterX does — a lot of it runs on their servers, which you can't see. But even just figuring out the client-side behavior can help you build your own workaround for specific sites. Just remember: this stuff changes often! PerimeterX updates their system regularly, so if you go down this path, expect to keep fixing things as they break.
Frequently asked questions
Is there a way to tell if a site uses PerimeterX?
Sometimes. Look at the page source or network traffic. If you see things like pxhd
cookies, px.js
, perimeterx.net
, or HUMAN branding, you're probably dealing with it. If you get the "Press & Hold" box, that's obviously a clear sign too. But sometimes it runs quietly in the background with no warning and it's somewhat hard to spot.
Can we completely bypass PerimeterX?
You can often avoid getting caught or at least reduce how often you get flagged. But fully bypassing PerimeterX forever? Probably not. It keeps changing and learning. You tweak something, it adjusts — and the cat-and-mouse game continues. No single trick works forever.
Can't we just use cached versions of websites?
You could try scraping Google Cache or the Wayback Machine — but most of the time, those pages are outdated, missing parts, or don't show dynamic content. They also won't help with stuff that changes often, like prices or product stock. They're fine for quick testing, but not great for real scraping work.
What happens if my scraper gets blocked?
You'll usually see challenge pages, weird redirects or just no data. Some pages might not load at all. When that happens, double-check your setup: maybe it's your IP, headers, speed, or something in the behavior. Even small changes — like using a different proxy or slowing down — can help.
Do I need all these tricks for every site?
Nope! Most websites don't use heavy bot protection. If you're scraping a smaller site, basic tools might be enough. Don't make things harder than they need to be — save the advanced tools for the tough ones.
Conclusion
Bypassing PerimeterX (HUMAN) isn't easy — and that's the point. It's made to stop bots and it does a solid job. But with the right tools and a smart approach, it's still possible to get through. Whether you use a scraping API, a stealth browser like Camoufox, or go full DIY, the key is knowing how the system works — and avoiding its red flags.
And as always: scrape responsibly. Some sites just aren't worth the hassle. But when you do need to take on the big ones, now you've got a few solid tools in your kit.
Good luck — and may your scrapers stay under the radar.

Ilya is an IT tutor and author, web developer, and ex-Microsoft/Cisco specialist. His primary programming languages are Ruby, JavaScript, Python, and Elixir. He enjoys coding, teaching people and learning new things. In his free time he writes educational posts, participates in OpenSource projects, tweets, goes in for sports and plays music.