Camofox Browser
Camofox architecture: user contexts, tab groups, page leases and idle recovery
Trace the server’s browser lifecycle and distinguish isolation of browser state from caller authorization and resource admission.
What you will learn
- A user context contains tab groups; groups are not separate cookie contexts.
- Page leases represent creation before group attachment.
- Admission, recycling, expiry and idle shutdown need separate handling.
Before you start
- Basic HTTP and JSON knowledge
- An isolated service and an owned or permitted test page
Explain the chapter’s actual service boundary and verify the proposed observation or lifecycle fixture.
Key takeaways
- A user context contains tab groups; groups are not separate cookie contexts.
- Page leases represent creation before group attachment.
- Admission, recycling, expiry and idle shutdown need separate handling.
Map the state hierarchy precisely
getSession normalizes userId and looks it up in a sessions map. A new session obtains a browser context, while tabGroups organize pages beneath that session. A sessionKey selects a group; a tab ID selects a particular tab state. This hierarchy helps explain why two groups for one user are not automatically two independent cookie contexts.
Existing sessions are checked for closing state and a live context. Creation is coalesced per user so overlapping requests can share the in-flight creation rather than independently constructing duplicate sessions. This is resource coordination, not identity verification. Authorization must decide which caller may supply which userId before that identifier reaches the browser-state machinery.
A page can exist before it belongs to a tab group
The small page-lease helper tracks a page while it exists outside the normal group structure. A lease begins before the page has been attached, can later hold the created page, and is released once the transition is complete. Reapers can use active leases to avoid treating a session as empty during page creation. This is a useful example of representing an intermediate lifecycle state explicitly.
Admission and recycling are different branches. getSession rejects when the configured session ceiling is reached; the tab-creation handler attempts to recycle an old tab when tab limits are reached, and rejects if recycling cannot succeed. A client should not assume that opening one more tab leaves every earlier tab untouched. Observe the returned state and retain only current tab identifiers.
Recovery changes the meaning of readiness
The health handler distinguishes recovery and unexpected browser absence from an intentional idle stop. Recovery can produce a 503 response, while an intentionally stopped browser can still leave the service healthy. This prevents an idle optimization from being mistaken for a process outage, but it requires operators to use separate checks for service reachability and browser workload readiness.
The inspected configuration includes session timeout, tab inactivity, browser idle timeout, per-user concurrency and global limits. These controls are not interchangeable: one expires state, another bounds work, and another reclaims a browser process. Test the lifecycle with an owned fixture and explain which control caused a tab to disappear before changing all timeouts or increasing capacity together.
Implementation steps
- 1
Draw browser, user context, group and tab state separately.
- 2
Trace a page through lease acquisition, attachment and release.
- 3
Exercise a small test limit and observe recycling or rejection.
- 4
Distinguish idle health from a failed page-readiness check.
Copy-ready example
Browser
user context
sessionKey A -> tab 1, tab 2
sessionKey B -> tab 3
Page creation: acquire lease -> create page -> attach -> release lease
Caller authorization is a separate boundary.Frequently asked questions
Do separate sessionKey values isolate cookies?
Not by themselves. The inspected hierarchy places tab groups under a user browser context; use the context boundary when reasoning about browser state.
Why track an unattached page?
A page lease prevents cleanup logic from treating the session as empty during the intermediate creation state.
Sources
- README.mdSource checked 2026-09-08
- package.jsonSource checked 2026-09-08
- DockerfileSource checked 2026-09-08
- lib/auth.jsSource checked 2026-09-08
- lib/snapshot.jsSource checked 2026-09-08
- lib/extract.jsSource checked 2026-09-08
- lib/config.jsSource checked 2026-09-08
- lib/reporter.jsSource checked 2026-09-08
- lib/page-lease.jsSource checked 2026-09-08
- server.jsSource checked 2026-09-08
- tests/unit/snapshot.test.jsSource checked 2026-09-08
- tests/unit/auth.test.jsSource checked 2026-09-08