Skip to content

vs hrequests

github-actions[bot] edited this page Nov 13, 2026 · 7 revisions

invisible_playwright vs hrequests

hrequests pairs a TLS-impersonating HTTP client with a browser mode that launches someone else's anti-detect browser instead of driving one of its own; invisible_playwright is a single browser whose fingerprint comes from inside a patched engine it maintains directly, so there is no separate upstream project standing between the fingerprint and the page. hrequests, by daijro, is unusual among the tools on these comparison pages because it is two tools in one package: a TLS-impersonating HTTP client for requests that never open a browser, and an optional browser mode for the pages that need one. That hybrid design is the interesting part, and it means the comparison is really two comparisons, because each mode makes a different trade.

This page walks the two modes, names the seam each one carries, and shows where a fingerprint that lives in the browser engine lands differently. hrequests was last pushed on 2024-12-01 at time of writing, so this is a comparison of a real, working project against a different architecture, not a claim that anything is abandoned.

What hrequests actually is

hrequests wraps two capabilities behind one requests-shaped API. The first is an HTTP client that impersonates a real browser's TLS and HTTP/2 handshake, so a plain get carries a handshake that matches the user agent it claims, with headers generated by BrowserForge, daijro's own open-source header and fingerprint generator. The second is a browser mode, reached by rendering a response, that launches Camoufox, also daijro's project, for a Firefox session by default, or Patchright for a Chrome one - two separately maintained anti-detect projects, not code written inside hrequests itself.

The usual flow is to start in the HTTP client, and only escalate to the browser when a page needs JavaScript:

import hrequests

resp = hrequests.get("https://example.com")   # TLS-impersonating HTTP, no browser
if "the value you need" not in resp.text:
    page = resp.render()                      # escalate to a real browser
    html = page.html
    page.close()

That escalation is the whole idea, and it is a genuinely good one for the class of target where most pages are static and a few are not. The two comparisons below are about what each half of it costs.

The HTTP mode: fast because it runs no JavaScript

The HTTP client is fast for one concrete reason: it never executes any JavaScript. It does the handshake, sends the request, and hands you the bytes. For a page whose data is already in the initial HTML, that is the correct tool and nothing heavier is justified.

The limit is the same as its speed. A page that builds its content with client-side JavaScript comes back to an HTTP client as a near-empty shell, and a page that runs a script to decide what to serve sees a client that ran no script. This is the TLS-and-headers vs a real engine split that decides whether an HTTP request is enough: matching the handshake gets you past the network layer, but it does not run the page, so anything the page computes in the browser is not there.

So the HTTP mode's trade is explicit: maximum speed, zero JavaScript, and it works exactly up to the point where the target expects a browser to have run something.

The browser mode: two upstream projects, not hrequests' own layer

When hrequests escalates to its browser mode, it is not running its own stealth code. The default path launches Camoufox, a separately maintained Firefox build that patches the fingerprint into the C++ engine, the same layer this project uses, with a different identity model: Camoufox rotates a fresh device per session instead of deriving one from a seed. For a Chrome session hrequests hands off to Patchright instead, a fork of Playwright that patches the automation driver's CDP session instead of the engine or the page. By hrequests' own documentation, the Chrome path does not get fingerprint rotation, human-like mouse movement, or extension support, which is why the project recommends Firefox.

So the seam to look for depends on which engine you asked for. A Camoufox-backed Firefox session has no page-layer injection to catch, for the same reason invisible_playwright has none: the value never lived anywhere else first. A Patchright-backed Chrome session has a different kind of tell, the CDP-session artifacts a driver patch fixes rather than a fingerprint generator, and by hrequests' own admission it ships without several of the browser mode's headline features on that path.

None of this makes hrequests' browser mode a bad choice. It makes it a wrapper around two other projects rather than a fingerprint layer of its own, and which guarantees you get depends on which of the two you end up driving.

Where invisible_playwright differs: the fingerprint is in the engine

invisible_playwright does not inject a fingerprint into a page. The values are what a patched Firefox returns natively, from inside the C++ engine, so there is no later override to catch: JavaScript in the page reads the spoofed value the first time and every time, and a read is just a read. Stock Playwright drives that engine with no wrapped subset of the API to learn.

Switching from plain Playwright is two lines, and the returned object is a real Playwright Browser:

from invisible_playwright import InvisiblePlaywright

with InvisiblePlaywright(seed=42) as browser:
    page = browser.new_page()
    page.goto("https://example.com")
    page.click("#submit")   # mouse arcs to the button on a Bezier curve

The seed is the second difference. One seed derives one coherent identity - GPU, canvas hash, audio context, fonts, screen - and passing the same seed reproduces it field for field, which is what makes a failing run replayable instead of a fresh random draw every time. Behind a proxy the browser timezone is auto-derived from the egress IP by default:

proxy = {"server": "socks5://gate.example.com:1080", "username": "u", "password": "p"}
with InvisiblePlaywright(proxy=proxy, seed=42) as browser:
    page = browser.new_page()
    page.goto("https://example.com")

Because the TLS handshake is Firefox's own real handshake rather than an impersonation of it, the handshake and the user agent tell the same story by construction, which is the network-layer half of what the HTTP mode gets from impersonation and the browser mode has to get separately.

The honest caveat: this is a full browser, so it is heavier and slower than a JavaScript-less HTTP fetch, and it never claims to fix the two things no browser property controls. A datacenter IP is still a datacenter IP, and machine-shaped behaviour is still a signal. A real engine removes the fingerprint seam; it does not remove your address or your mouse path.

hrequests and invisible_playwright side by side

The two hrequests modes and invisible_playwright differ on one axis that decides everything: whether JavaScript runs, and if it does, whose engine is running it. A mode that runs no script has no JS surface to fingerprint; a mode that hands the page to a separately maintained browser inherits whatever that browser's own approach is; an engine that returns the value natively, in code this project maintains directly, leaves no seam and no dependency on someone else's release schedule.

What a detector checks hrequests HTTP mode hrequests browser mode invisible_playwright
Runs JavaScript No Yes Yes
Network handshake TLS impersonation Real browser's handshake Firefox's own real handshake
Where the fingerprint lives No JS surface to fingerprint Camoufox's C++ engine (Firefox, default) or Patchright's CDP patch (Chrome) Returned natively by this project's own engine
Override seam to find None None via Camoufox; a CDP-session artifact via Patchright None
Relative speed Fastest Full browser Full browser

Choosing between them

The split is clean enough to state as a rule.

Reach for an HTTP client, hrequests' or otherwise, when the data is in the initial HTML and the target does not require a browser to have run. It is faster, lighter, and the right size for that job. Reach for a real browser when the page runs JavaScript to build or gate its content, and at that point the question becomes which engine is actually answering: one you maintain yourself, or one you are borrowing from someone else's project.

hrequests puts an HTTP client and a launcher for two other people's browsers in one package, which is a real convenience if you are happy with Camoufox's device rotation on Firefox or Patchright's reduced feature set on Chrome. invisible_playwright is a single product: the same engine supplies the fingerprint and the driver-level fixes, with nothing borrowed and nothing to keep in sync with an upstream release.

Conclusion

hrequests is a hybrid, and each half is a different trade. The HTTP mode is fast because it executes no JavaScript, and it stops working the moment a target expects a browser to have run something. The browser mode does not add a fingerprint layer of its own; it launches Camoufox or Patchright and inherits whichever guarantees that project ships. invisible_playwright takes the browser-mode job and keeps it in one codebase: the fingerprint is what its own patched engine returns natively, driven by stock Playwright, reproducible from a seed, with no second project's release cycle to track. If your work is mostly static pages with the occasional dynamic one, the hybrid's escalation is genuinely handy. If it is the dynamic pages that matter, owning the engine rather than borrowing one is the durable difference.

Short answers to the questions that lead here

Is hrequests abandoned? No claim here. Its last push was 2024-12-01 at time of writing, and everything above describes it as a working project with a real design.

What is the actual architectural difference? hrequests' browser mode launches Camoufox or Patchright rather than fingerprinting the page itself; invisible_playwright returns the fingerprint from inside its own C++ engine, with no upstream project in between.

Is the HTTP mode enough on its own? For pages whose data is in the initial HTML, yes, and it is faster than any browser. For pages that build content with client-side JavaScript, no, because an HTTP client runs no script.

Does injecting a good fingerprint pass a strict detector? Not reliably: the value can be perfect and the injection still leaves a seam - an override on the prototype chain, a toString that no longer reads native - which is exactly what CreepJS is built to surface. It is also not what hrequests' own browser mode does by default; Camoufox patches the engine instead.

Can I keep my existing Playwright code? Yes. invisible_playwright returns a real Playwright Browser, so every method works as documented upstream; the switch is two lines at launch.

Does a real engine mean I never get blocked? No. It removes the fingerprint seam. It does not change your IP reputation or your behaviour, and both of those are still measured.

Sources

  • daijro/hrequests, its own repository and README, read from source for the last-push date cited above, its TLS-impersonating HTTP client, and its browser mode's use of Camoufox and Patchright, retrieved 2026-08-28.
  • BrowserForge, the open-source header and fingerprint generator hrequests uses in its HTTP client, described from its own project, retrieved 2026-08-28.
  • Camoufox, also daijro's project and the C++-patched Firefox hrequests launches by default for its browser mode, and Patchright, the CDP-driver patch it launches for a Chrome session, both described from their own projects, retrieved 2026-08-28.
  • This project's own quickstart and configuration docs for the API shown, and its detection notes for what an injection seam looks like to a descriptor-walking suite.

See also: when a TLS-matching HTTP request is enough and when it is not, a toolkit that does inject a generated fingerprint into the page, and what CreepJS actually inspects.


Written while maintaining invisible_playwright, a Firefox patched at the C++ level driven by stock Playwright. The comparison is with a working project; the durable difference is the layer the fingerprint lives in, not who shipped last.

Documentation

Guides

Comparisons

Integrations

docs/ source folder

Clone this wiki locally