Reference

Browser Session Persistence for CAPTCHA Workflows

Every new browser session starts from zero — no cookies, no history, no trust. CAPTCHA systems see fresh sessions as risky and trigger challenges more frequently. Persisting sessions between runs builds trust, reduces CAPTCHA frequency, and avoids solving the same challenge repeatedly.


Why Session Persistence Reduces CAPTCHAs

Session State CAPTCHA Frequency Why
Fresh session (no cookies) High No trust history, unknown user
Session with Google cookies Medium reCAPTCHA recognizes Google login
Warmed session (browsing history) Low Organic behavior signals
Persistent profile (days old) Very low Established trust score

Save and Restore Cookies

import json
import os
import time
from selenium import webdriver


class PersistentSession:
    def __init__(self, profile_name="default", cookie_dir="./sessions"):
        self.profile_name = profile_name
        self.cookie_dir = cookie_dir
        self.cookie_file = os.path.join(cookie_dir, f"{profile_name}_cookies.json")
        os.makedirs(cookie_dir, exist_ok=True)

    def create_driver(self):
        options = webdriver.ChromeOptions()
        options.add_argument("--disable-blink-features=AutomationControlled")
        options.add_argument("--window-size=1920,1080")
        return webdriver.Chrome(options=options)

    def save_cookies(self, driver):
        """Save all cookies to disk."""
        cookies = driver.get_cookies()
        with open(self.cookie_file, "w") as f:
            json.dump(cookies, f, indent=2)
        print(f"Saved {len(cookies)} cookies to {self.cookie_file}")

    def load_cookies(self, driver, domain=None):
        """Restore cookies from disk."""
        if not os.path.exists(self.cookie_file):
            print("No saved cookies found")
            return False

        with open(self.cookie_file) as f:
            cookies = json.load(f)

        loaded = 0
        for cookie in cookies:
            # Filter by domain if specified
            if domain and domain not in cookie.get("domain", ""):
                continue

            # Remove problematic fields
            cookie.pop("sameSite", None)
            cookie.pop("storeId", None)

            try:
                driver.add_cookie(cookie)
                loaded += 1
            except Exception as e:
                print(f"Skip cookie {cookie.get('name')}: {e}")

        print(f"Loaded {loaded}/{len(cookies)} cookies")
        return loaded > 0

    def run_with_session(self, url, callback):
        """Run a task with persistent session."""
        driver = self.create_driver()

        try:
            # Navigate to domain first (required for cookie loading)
            driver.get(url)
            time.sleep(1)

            # Load saved cookies
            self.load_cookies(driver)

            # Refresh to apply cookies
            driver.get(url)
            time.sleep(2)

            # Execute task
            result = callback(driver)

            # Save updated cookies
            self.save_cookies(driver)

            return result

        finally:
            driver.quit()


# Usage
session = PersistentSession("target-site")

def my_task(driver):
    # Check if already logged in
    if "dashboard" in driver.current_url:
        print("Session restored — no login needed")
        return driver.page_source
    else:
        print("Need to login + solve CAPTCHA")
        # Solve CAPTCHA with CaptchaAI...
        return None

result = session.run_with_session("https://example.com", my_task)

Chrome User Data Directory (Full Profile Persistence)

The most complete persistence — saves cookies, localStorage, cache, history, and browser state:

import os
from selenium import webdriver

PROFILE_DIR = os.path.abspath("./chrome-profiles/profile-1")


def create_persistent_driver():
    options = webdriver.ChromeOptions()
    options.add_argument(f"--user-data-dir={PROFILE_DIR}")
    options.add_argument("--profile-directory=Default")
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_argument("--no-sandbox")
    return webdriver.Chrome(options=options)


# First run: builds fresh profile
driver = create_persistent_driver()
driver.get("https://example.com")
# ... solve CAPTCHA, login, etc.
driver.quit()

# Second run: same profile, cookies and state preserved
driver = create_persistent_driver()
driver.get("https://example.com")
# Often skips CAPTCHA because session is recognized
driver.quit()

Benefits of User Data Directory

What's Preserved Impact on CAPTCHAs
Cookies Session tokens, Google NID cookie
localStorage Site-specific trust tokens
IndexedDB reCAPTCHA internal state
Cache Faster page loads
History Browsing pattern signals
Service workers Background CAPTCHA checks

Puppeteer Persistent Context

const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
const path = require("path");

puppeteer.use(StealthPlugin());

const USER_DATA_DIR = path.resolve("./chrome-profiles/profile-1");

async function runWithPersistentProfile() {
  const browser = await puppeteer.launch({
    headless: false,
    userDataDir: USER_DATA_DIR,
    args: [
      "--no-sandbox",
      "--window-size=1920,1080",
    ],
  });

  const page = await browser.newPage();
  await page.goto("https://example.com", { waitUntil: "networkidle0" });

  // Check if session is active
  const isLoggedIn = await page.evaluate(() =>
    document.querySelector(".user-menu") !== null
  );

  if (isLoggedIn) {
    console.log("Session active — no CAPTCHA needed");
  } else {
    console.log("Session expired — solving CAPTCHA");
    // Solve with CaptchaAI...
  }

  await browser.close();
}

localStorage and sessionStorage

def save_storage(driver, filepath):
    """Save localStorage and sessionStorage."""
    storage = driver.execute_script("""
        return {
            localStorage: Object.fromEntries(
                Object.entries(localStorage)
            ),
            sessionStorage: Object.fromEntries(
                Object.entries(sessionStorage)
            ),
        };
    """)

    with open(filepath, "w") as f:
        json.dump(storage, f, indent=2)


def restore_storage(driver, filepath):
    """Restore localStorage and sessionStorage."""
    if not os.path.exists(filepath):
        return

    with open(filepath) as f:
        storage = json.load(f)

    for key, value in storage.get("localStorage", {}).items():
        driver.execute_script(
            f"localStorage.setItem('{key}', '{value}')"
        )

    for key, value in storage.get("sessionStorage", {}).items():
        driver.execute_script(
            f"sessionStorage.setItem('{key}', '{value}')"
        )

Session Warming Strategy

New sessions trigger more CAPTCHAs. "Warming" a session with organic behavior builds trust:

import random
import time

def warm_session(driver, warm_urls=None):
    """Simulate organic browsing to build session trust."""
    default_urls = [
        "https://www.google.com",
        "https://www.google.com/search?q=weather",
        "https://www.wikipedia.org",
    ]

    urls = warm_urls or default_urls

    for url in urls:
        driver.get(url)
        time.sleep(random.uniform(2, 5))

        # Simulate scroll
        driver.execute_script(
            f"window.scrollTo(0, {random.randint(200, 800)})"
        )
        time.sleep(random.uniform(1, 3))

    print(f"Session warmed with {len(urls)} pages")


# Usage
driver = create_persistent_driver()
warm_session(driver)

# Now navigate to target — lower CAPTCHA chance
driver.get("https://target-site.com/form")

Multi-Profile Session Manager

import os
import json
import time
from datetime import datetime


class SessionManager:
    """Manage multiple persistent browser profiles."""

    def __init__(self, base_dir="./sessions"):
        self.base_dir = base_dir
        self.meta_file = os.path.join(base_dir, "profiles.json")
        os.makedirs(base_dir, exist_ok=True)

        if os.path.exists(self.meta_file):
            with open(self.meta_file) as f:
                self.profiles = json.load(f)
        else:
            self.profiles = {}

    def _save_meta(self):
        with open(self.meta_file, "w") as f:
            json.dump(self.profiles, f, indent=2)

    def get_profile_dir(self, name):
        return os.path.join(self.base_dir, f"profile-{name}")

    def create_profile(self, name, proxy=None):
        """Create a new browser profile."""
        profile_dir = self.get_profile_dir(name)
        os.makedirs(profile_dir, exist_ok=True)

        self.profiles[name] = {
            "created": datetime.now().isoformat(),
            "last_used": None,
            "use_count": 0,
            "proxy": proxy,
            "captcha_solves": 0,
        }
        self._save_meta()
        return profile_dir

    def get_least_used_profile(self):
        """Get the profile used least recently."""
        if not self.profiles:
            return None

        return min(
            self.profiles.items(),
            key=lambda x: x[1].get("last_used") or ""
        )[0]

    def record_use(self, name, solved_captcha=False):
        """Record profile usage."""
        if name in self.profiles:
            self.profiles[name]["last_used"] = datetime.now().isoformat()
            self.profiles[name]["use_count"] += 1
            if solved_captcha:
                self.profiles[name]["captcha_solves"] += 1
            self._save_meta()

    def get_stats(self):
        """Print profile statistics."""
        for name, meta in self.profiles.items():
            print(f"Profile: {name}")
            print(f"  Uses: {meta['use_count']}")
            print(f"  CAPTCHAs: {meta['captcha_solves']}")
            print(f"  Last used: {meta.get('last_used', 'never')}")
            print()


# Usage
manager = SessionManager()

# Create 5 rotating profiles
for i in range(5):
    manager.create_profile(f"worker-{i}")

# Get next profile to use
profile_name = manager.get_least_used_profile()
profile_dir = manager.get_profile_dir(profile_name)

# Use with Selenium
options = webdriver.ChromeOptions()
options.add_argument(f"--user-data-dir={os.path.abspath(profile_dir)}")
driver = webdriver.Chrome(options=options)

# After task
manager.record_use(profile_name, solved_captcha=True)
manager.get_stats()

from datetime import datetime, timezone


def clean_expired_cookies(cookie_file):
    """Remove expired cookies from saved file."""
    if not os.path.exists(cookie_file):
        return

    with open(cookie_file) as f:
        cookies = json.load(f)

    now = datetime.now(timezone.utc).timestamp()
    valid = [c for c in cookies if c.get("expiry", float("inf")) > now]

    removed = len(cookies) - len(valid)
    if removed > 0:
        with open(cookie_file, "w") as f:
            json.dump(valid, f, indent=2)
        print(f"Removed {removed} expired cookies")


def merge_cookies(existing_file, new_cookies):
    """Merge new cookies with existing, preferring newer values."""
    existing = []
    if os.path.exists(existing_file):
        with open(existing_file) as f:
            existing = json.load(f)

    # Index by (name, domain)
    cookie_map = {}
    for c in existing:
        key = (c["name"], c.get("domain", ""))
        cookie_map[key] = c

    for c in new_cookies:
        key = (c["name"], c.get("domain", ""))
        cookie_map[key] = c  # Newer overwrites

    merged = list(cookie_map.values())
    with open(existing_file, "w") as f:
        json.dump(merged, f, indent=2)

    return len(merged)

Troubleshooting

Issue Cause Fix
Cookies not loading Haven't navigated to domain first Call driver.get(url) before add_cookie
Profile locked error Previous Chrome didn't close Kill Chrome processes, remove SingletonLock
Session still expired Cookie sameSite mismatch Remove sameSite before loading
Storage blocked CORS/security context Load storage after navigating to correct origin
Higher CAPTCHA rate over time IP flagged Rotate proxies per profile

FAQ

How long do browser sessions reduce CAPTCHA frequency?

Google's NID cookie lasts 6 months. Cloudflare's cf_clearance typically lasts 15 minutes to 1 hour. Persist and refresh regularly.

Can I share sessions between machines?

Yes — export cookie files and user-data-dir folders. Match the timezone and proxy to the original session for best results.

Does session persistence work with headless Chrome?

Yes. User data directories and cookie files work identically in headless mode. The stored cookies carry the same trust signals.

How many profiles should I maintain?

For rotating use, maintain 5-10 profiles per target site. Rotate usage to avoid rate-limiting any single profile.

Does CaptchaAI benefit from session persistence?

Indirectly — session persistence reduces CAPTCHA frequency, lowering the number of CaptchaAI calls needed (saving cost). When CAPTCHAs do appear, CaptchaAI solves them as usual.



Build persistent browser sessions that reduce CAPTCHA challenges — get your CaptchaAI key for when challenges still appear.

Discussions (0)

No comments yet.

Related Posts

Reference CAPTCHA Token Injection Methods Reference
Complete reference for injecting solved CAPTCHA tokens into web pages.

Complete reference for injecting solved CAPTCHA tokens into web pages. Covers re CAPTCHA, Turnstile, and Cloud...

Automation Python reCAPTCHA v2
Apr 08, 2026
Use Cases CAPTCHA Solving in Ticket Purchase Automation
How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automated purchasing workflows.

How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automate...

Automation Python reCAPTCHA v2
Feb 25, 2026
Tutorials Caching CAPTCHA Tokens for Reuse
Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs.

Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs. Covers token lifetimes, cache st...

Automation Python reCAPTCHA v2
Feb 15, 2026
Use Cases Multi-Step Checkout Automation with CAPTCHA Solving
Automate multi-step e-commerce checkout flows that include CAPTCHA challenges at cart, payment, or confirmation stages using Captcha AI.

Automate multi-step e-commerce checkout flows that include CAPTCHA challenges at cart, payment, or confirmatio...

Automation Python reCAPTCHA v2
Mar 21, 2026
Comparisons Headless vs Headed Chrome for CAPTCHA Solving
Compare headless and headed Chrome for CAPTCHA automation — detection differences, performance trade-offs, and when to use each mode with Captcha AI.

Compare headless and headed Chrome for CAPTCHA automation — detection differences, performance trade-offs, and...

Automation Python reCAPTCHA v2
Mar 09, 2026
API Tutorials CaptchaAI API Latency Optimization: Faster Solves
Reduce CAPTCHA solve latency with Captcha AI by optimizing poll intervals, connection pooling, prefetching, and proxy selection.

Reduce CAPTCHA solve latency with Captcha AI by optimizing poll intervals, connection pooling, prefetching, an...

Automation Python reCAPTCHA v2
Feb 27, 2026
Use Cases CAPTCHA Handling for Sneaker Bot Automation
How sneaker bots handle CAPTCHAs on Nike, Adidas, Footlocker, and other release sites using Captcha AI for fast checkout.

How sneaker bots handle CAPTCHAs on Nike, Adidas, Footlocker, and other release sites using Captcha AI for fas...

Automation Python reCAPTCHA v2
Feb 04, 2026
API Tutorials Building a Python Wrapper Library for CaptchaAI API
Build a reusable Python wrapper library for the Captcha AI API with type hints, retry logic, context managers, and support for CAPTCHA types.

Build a reusable Python wrapper library for the Captcha AI API with type hints, retry logic, context managers,...

Automation Python reCAPTCHA v2
Jan 31, 2026
Tutorials Pytest Fixtures for CaptchaAI API Testing
Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI.

Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI. Covers mocking, live integra...

Automation Python reCAPTCHA v2
Apr 08, 2026
Integrations Browser Profile Isolation + CaptchaAI Integration
Browser profile isolation tools create distinct browser environments with unique fingerprints per session.

Browser profile isolation tools create distinct browser environments with unique fingerprints per session. Com...

Automation Python reCAPTCHA v2
Feb 21, 2026
Reference API Endpoint Mapping: CaptchaAI vs Competitors
Side-by-side API endpoint comparison between Captcha AI, 2 Captcha, Anti-Captcha, and Cap Monster — endpoints, parameters, and response formats.

Side-by-side API endpoint comparison between Captcha AI, 2 Captcha, Anti-Captcha, and Cap Monster — endpoints,...

All CAPTCHA Types Migration
Feb 05, 2026
Reference CaptchaAI CLI Tool: Command-Line CAPTCHA Solving and Testing
A reference for building and using a Captcha AI command-line tool — solve CAPTCHAs, check balance, test parameters, and integrate with shell scripts and CI/CD p...

A reference for building and using a Captcha AI command-line tool — solve CAPTCHAs, check balance, test parame...

Automation Python All CAPTCHA Types
Feb 26, 2026
Reference CAPTCHA Solving Performance by Region: Latency Analysis
Analyze how geographic region affects Captcha AI solve times — network latency, proxy location, and optimization strategies for global deployments.

Analyze how geographic region affects Captcha AI solve times — network latency, proxy location, and optimizati...

Automation Python All CAPTCHA Types
Apr 05, 2026