Skip to content

Keep one proxy exit for the whole run on a 2Captcha gateway - #20

Merged
jehrr merged 1 commit into
mainfrom
fix/proxy-sticky-session-2026-10-22
Oct 22, 2026
Merged

jehrr merged 1 commit into
mainfrom
fix/proxy-sticky-session-2026-10-22

Conversation

@jehrr

@jehrr jehrr commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

VRBO_PROXY is a 2Captcha residential gateway login of the form ACCOUNT-zone-custom-region-US, with no session segment. Such a login may be answered from a different residential address on each connection. A results walk is one browser session that turns pages with a button press, so page 3 could replay page 1's cookies from a different exit. The pagination canary's page-turn refusals have never been tested against a single, fixed exit.

Resulting behaviour

  • When the proxy host is under .proxy.2captcha.com or .proxy.rucaptcha.com and the login names no -session-, the run appends one random -session-<12 alnum>-sessTime-<N> to the login. This happens once, before the pre-check and before any browser. Every request of the run then uses that login: the pre-check, page 1, the page turns and any relaunch.
  • --proxy-session-minutes N (all three engines; also VRBO_PROXY_SESSION_MINUTES) sets N. The default is 30, and the accepted range is 0 to 120 (the IP-duration range the vendor's residential dashboard offers). 0 sends the login unchanged. Negative, over-range and non-numeric values exit 2 and name the flag. A bad environment value exits instead of falling back to the default.
  • Logins left exactly as given:
    • a login that already names a session;
    • any proxy that is not a gateway, including lookalike hosts that only contain the gateway name;
    • an IP-whitelisted gateway URL with no login.
  • A login with only -sessTime- keeps its own duration and gains an id.
  • With --proxy-file, duplicates are dropped first, then each gateway line gets its own id. Rotation is still a new browser on another entry's own session. Entries never change after the pool is built, so the proxy under a live browser never changes.
  • The sidecar gains proxy_session_pinned: true/false. The id itself is never recorded, and the log masks the whole login. Selenium records false because it strips proxy credentials (it has no way to send them).

Evidence

Offline suite, PYTHONDONTWRITEBYTECODE=1, caches cleared between runs:

venv checks passed result skipped
core 723 OK the three engine groups, which need their libraries
playwright 743 OK only the sibling engines
selenium 742 OK only the sibling engines
pyppeteer 742 OK only the sibling engines

No browsers were downloaded. ci_checks.py --help-check --sample-check --secret-check passed.

New group test_proxy_sticky_session, 38 checks, covering:

  • the rewrite, and the cases left alone;
  • one login across repeated reads and the pre-check (with proxy_check.precheck stubbed, so no request leaves the machine);
  • a fresh id per run;
  • 0 = off, and the environment variable;
  • file de-duplication before pinning, and rotation;
  • the sidecar field;
  • flag validation, and the wiring in each engine.

Each engine is also driven through scrape(), with the page fetch and the pre-check stubbed, on a gateway login and on a non-gateway proxy. Each asserts proxy_session_pinned in <out>.meta.json, and that no session id appears in the sidecar or the log.

Planted-fault controls. Each one turned the suite red on its named check, and the restored tree was green:

  1. Never appending.
  2. Overwriting an existing session.
  3. Substring host match.
  4. Pinning before de-duplication.
  5. Re-minting on every read of the current exit.
  6. Overriding the caller's -sessTime-.
  7. Recording the id in the sidecar.
  8. Accepting negative minutes.
  9. Selenium claiming true (red on the source check and on the driven run in the selenium venv).
  10. Playwright dropping the sidecar field.
  11. pyppeteer lacking the flag.

No paid calls and no proxy traffic were used for these checks.

Not changed

🤖 Generated with Claude Code

https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8

A gateway login with no -session- segment can be answered from a different
residential address on each connection, so a results walk could replay page
1's cookies from another exit. When the proxy host is under
.proxy.2captcha.com or .proxy.rucaptcha.com and the login names no session,
the run now appends one random -session-<id>-sessTime-<N> (N from
--proxy-session-minutes / VRBO_PROXY_SESSION_MINUTES, default 30, 0 = off),
once, before the pre-check and the browser. A login that already names a
session is left as given; with --proxy-file each gateway line gets its own
id after de-duplication. The sidecar records proxy_session_pinned, never the
id; Selenium records false because it cannot send a proxy login.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8
@jehrr
jehrr merged commit fd5e1c8 into main Oct 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant