Fingerprint Management & Session Persistence: Make Your Scraper Look Like a Returning Visitor
Why random fingerprints trigger reCAPTCHA Enterprise, and how fixed seeds with persistent contexts make your scraper look like a returning user.
The Problem: Fresh Fingerprints Every Time Are Suspicious
CloakBrowser generates a random fingerprint seed on every launch by default — GPU model, hardware concurrency, screen dimensions are all new. This is fine for one-off scraping, but when you visit the same target repeatedly:
Same IP, same account, but a different browser fingerprint every time → the detection system sees multiple devices sharing one exit. Highly suspicious.
reCAPTCHA v3 Enterprise maintains a long-term behavioral profile of each user. A new fingerprint every visit = a new user every visit. Your accumulated trust score resets to zero.
Fixed Fingerprint Seeds
CloakBrowser supports deterministic fingerprints via --fingerprint:
from cloakbrowser import launch
# Fixed seed 12345 — identical fingerprint across launches
browser = launch(args=["--fingerprint=12345"])
import { launch } from 'cloakbrowser';
const browser = await launch({ args: ['--fingerprint=12345'] });
Seed Strategy Guide
| Scenario | Strategy | Why |
|---|---|---|
| One-off bulk scrape | Random seed (default) | Fresh identity per task |
| Sites requiring login | Fixed seed + persistent context | Identity + session both persist |
| Multi-account | One fixed seed per account | Simulate multiple devices |
| With dedicated proxy | Bind seed to proxy IP | Same IP + same fingerprint = fixed device |
Platform Fingerprint Override
CloakBrowser spoofs Linux to Windows by default. Override for cross-platform needs:
browser = launch(args=[
"--fingerprint=12345",
"--fingerprint-platform=macos",
])
Persistent Contexts: Login State That Survives Restarts
launch_persistent_context() preserves cookies, localStorage, and cache across sessions:
from cloakbrowser import launch_persistent_context
# First run — create and save profile
ctx = launch_persistent_context("./my-profile", headless=False)
page = ctx.new_page()
page.goto("https://example.com/login")
page.fill("#username", "myaccount")
page.fill("#password", "mypassword")
page.click("button[type=submit]")
# Scrape...
ctx.close() # profile auto-saved
# Second run — cookies, localStorage restored
ctx = launch_persistent_context("./my-profile", headless=False)
page = ctx.new_page()
page.goto("https://example.com/dashboard")
# Already logged in!
Key use cases:
- Authenticated scraping: Scheduled tasks resume login state automatically
- Incognito detection bypass: Persistent contexts show as non-incognito
- Chrome extensions: Extensions only work from a real user data directory
- Natural browsing history: Cached fonts, Service Workers, IndexedDB accumulate over time
With 16Yun Dedicated Proxy
A dedicated proxy with a fixed exit IP + fixed fingerprint seed + persistent context = a convincing "office computer" in the detection system's eyes:
from cloakbrowser import launch_persistent_context
ctx = launch_persistent_context(
"./my-profile",
headless=False,
proxy="http://user:pass@dedicated.16yun.cn:8888",
)
Storage Quota Tradeoff
CloakBrowser normalizes storage quota to pass FingerprintJS. This may cause BrowserScan's notPrivate check to flag incognito mode.
| Quota Setting | FingerprintJS | BrowserScan notPrivate |
|---|---|---|
| Default (~500MB) | ✅ PASS | ⚠️ Flagged as incognito |
--fingerprint-storage-quota=5000 | May trigger detection | ✅ Non-incognito |
Use the default quota if the target runs FingerprintJS. Increase quota if the target cares more about incognito detection:
ctx = launch_persistent_context(
"./my-profile",
args=["--fingerprint-storage-quota=5000"],
)
Quick Context (No Persistence)
For one-off sessions without profile persistence:
from cloakbrowser import launch_context
context = launch_context(
user_agent="Custom UA",
viewport={"width": 1920, "height": 1080},
locale="en-US",
timezone="America/New_York",
)
page = context.new_page()
page.goto("https://example.com")
context.close()
Extra kwargs forward to Playwright's browser.new_context() — use storage_state, permissions, extra_http_headers, etc.
Save and Restore Session State
from cloakbrowser import launch_context
context = launch_context(storage_state="state.json")
page = context.new_page()
page.goto("https://example.com")
# ... interact ...
context.storage_state(path="state.json")
context.close()
Summary
| Technique | Problem Solved | CloakBrowser API |
|---|---|---|
| Fixed seed | Consistent fingerprint = returning visitor | args=["--fingerprint=12345"] |
| Persistent context | Login state, cookies, localStorage across restarts | launch_persistent_context("./profile") |
| Quota tuning | Balance FingerprintJS vs BrowserScan detection | --fingerprint-storage-quota=N |
| Proxy + fingerprint binding | Same IP + same fingerprint = maximum trust | Fixed proxy + fixed seed + persistent context |
Need an enterprise proxy plan?
We can tailor architecture to your target domains, concurrency, and reliability goals.