Anchor
Start from Tenki's pre-built Anchor image and connect to a remote browser over CDP.
Tenki's public tenki/anchor:stable image starts with the standard sandbox base image and adds playwright-core plus the anchor-smoke command. It does not include a local browser, an Anchor API key, or a browser profile. Your code connects to an Anchor-managed browser over CDP.
Anchor Browser: production-grade browsers for agents
The missing piece for agents running in your sandbox.
Your sandbox gives agents a place to run. Anchor gives them a browser they can actually use once they get there. Together, that is the full stack an agent needs, compute and browser, without your team stitching it together.
Why agents need this:
Agents that reason well and click well still get stopped cold in production by things no model upgrade fixes:
- Bot detection: Cloudflare, Akamai, DataDome, and reCAPTCHA are built to keep automated browsers out.
- Authentication at scale: MFA and session management assume a human at a keyboard, and break down at hundreds or thousands of concurrent agent sessions.
- Fragile automations: dynamic pages and brittle selectors mean tasks slow down and fail as workflows get longer.
- Runaway cost: retries, token spend, and infra add up fast at scale.
What Anchor brings into your sandbox:
- 🛡️ Anchor Chromium: a hardened Chromium fork with humanized fingerprints and human-like mouse and keystroke behavior. Stealth mode, proxies, captcha solving, and Cloudflare Web Bot Auth are available as add-ons.
- 🌐 Anchor VPN: a geo-aware network built into the browser, so agent traffic looks like a trusted user rather than flagged datacenter or third-party proxy traffic. Anchor enables it per account.
- 🔐 Managed Authentication: Identities or browser profiles that carry saved credentials, MFA, and persistent sessions, so agents log in once and stay logged in. You attach them as session options.
- ⚡ Self-healing automation: the Web Action Cache in Anchor Tasks lets previously seen flows run deterministically instead of re-reasoning every click, so multi-hundred-step tasks stay fast and keep running when a page changes.
All of it runs on Anchor's side of the CDP connection. The Tenki image ships playwright-core ready to connect, so there is no browser-hardening layer for your team to build or maintain, and credentials never land in the image, template, or snapshot. None of these are on automatically. The sample below opens a default browser session; enabling them takes Anchor plan features or session options, and Anchor's documentation covers each one.
Start a session
Create an Anchor API key, export it locally, then pass it only to the session:
export ANCHOR_API_KEY=<your-anchor-api-key>
tenki sandbox create \
--image tenki/anchor:stable \
--env "ANCHOR_API_KEY=$ANCHOR_API_KEY" \
--name anchor-demoThe shell history contains the environment variable reference, not the key value. Do not add the key to a template, snapshot, source file, or image.
Run the built-in connectivity check:
tenki sandbox exec --session anchor-demo -- anchor-smoke https://example.comThe command creates an Anchor session, connects with Playwright, loads the requested URL, prints its final URL and title, and ends the Anchor session. A successful result looks like:
{ "url": "https://example.com/", "title": "Example Domain" }Terminate the Tenki session when you finish:
tenki sandbox terminate anchor-demoUse Playwright in your code
playwright-core is installed under /home/tenki/node_modules, so JavaScript and TypeScript projects below /home/tenki can import it without installing another copy. Create the Anchor session through its API, connect to the returned CDP URL, and always end the remote session in a finally block. The empty request body asks for a default session; pass session options there to attach a profile, an Identity, or a proxy.
import { chromium } from "playwright-core";
const apiKey = process.env.ANCHOR_API_KEY;
if (!apiKey) throw new Error("ANCHOR_API_KEY is required");
const response = await fetch("https://api.anchorbrowser.io/v1/sessions", {
method: "POST",
headers: {
"anchor-api-key": apiKey,
"content-type": "application/json",
},
body: "{}",
});
if (!response.ok) throw new Error(`Anchor returned HTTP ${response.status}`);
const payload = await response.json();
const session = payload.data ?? payload;
let browser;
try {
browser = await chromium.connectOverCDP(session.cdp_url);
const context = browser.contexts()[0] ?? (await browser.newContext());
const page = context.pages()[0] ?? (await context.newPage());
await page.goto("https://example.com");
console.log(await page.title());
} finally {
await browser?.close();
await fetch(`https://api.anchorbrowser.io/v1/sessions/${session.id}`, {
method: "DELETE",
headers: { "anchor-api-key": apiKey },
});
}Write the script into the sandbox or clone your project there, then run it with Node.js.
Pin an exact build
stable moves to each newly published build. When a workload has to stay on the exact build it was tested against, resolve the tag once and launch the snapshot reference it returns:
tenki sandbox registry resolve tenki/anchor:stable
# image_id : <image-id>
# snapshot_id : <snapshot-id>
tenki sandbox create --image tenki/anchor@<snapshot-id>A snapshot reference never moves, so it keeps launching that build after stable advances.