Run cypress tap in an AI agent sandbox
An agent can start Cypress, run a spec, and read the result without anyone at the keyboard.
Cloud coding agents such as Claude Code on the web and Cursor Cloud run in a
sandbox: an isolated container or virtual machine with no screen and no person to click
through the Cypress app. cypress tap reads from a
running Cypress app in open mode, so the sandbox has to run that app too. This
page covers what the sandbox needs and how an agent starts a session on its own.
The behavior described on this page relies on changes made in Cypress v16.3.0. Earlier versions of Cypress can be run inside sandboxes but may require additional setup and configuration.
How it fits together​
Three things run in the same sandbox:
- The agent, which runs shell commands.
- A Cypress app in open mode (
cypress open), with a browser it launches for the selected testing type. cypress tapcommands, which the agent runs to start specs and read results.
cypress tap finds the Cypress session through files on the same machine and
talks to it over local connections. It cannot reach a Cypress app running on
another machine, so the agent and Cypress have to share one sandbox.
Requirements​
- Cypress version 16.3.0 or greater
- A version of Node.js supported by Cypress. See System requirements.
- On Linux, the
xvfbpackage. A sandbox has no screen; Cypress starts a virtual one for the app and the browser using Xvfb. If you already have a display you want Cypress to use, set theDISPLAYenvironment variable and Cypress uses it. IfDISPLAYpoints to a display that is not running, Cypress starts its own. - Network access to the hosts in the table below.
- A supported browser. See Choose a browser.
Network access​
Many agent sandboxes block network traffic by default. Allow these hosts so the Cypress binary downloads and the app can reach its services:
| Host | Used for |
|---|---|
registry.npmjs.org | Installing the cypress npm package |
download.cypress.io | Finding and downloading the Cypress binary |
cdn.cypress.io | Downloading the Cypress binary |
api.cypress.io | Requests the Cypress App makes to Cypress Cloud |
In addition to the hosts above, you will need to ensure the sandbox is allowed to access any hosts used by your tests; this includes your UI, API, auth layers, and any other network resources your tests rely on. If your test suite relies on dependencies downloaded from repositories other than NPMJS you will need to configure those as well.
If your application is network-restricted (only accessible from your corporate VPN for example) then you will need to coordinate with your network security team to establish a method for a remote sandbox to access it. This may require use of a proxy or other advanced configuration.
Detecting an AI agent​
Cypress recognizes common coding agents from the environment variables they set. When an agent is detected,
certain UI behaviors are bypassed or automated to facilitate running headlessly.
If your agent is not recognized, set CYPRESS_AGENT_MODE=1 on the same command
line that starts Cypress. Note that some agents start a new shell for each
command, so it may be necessary to change how the environment variable is set
depending on how your agent works. See Environment variables.
Changes made in a sandbox​
When an agent runs inside a sandbox there is the possibility it could create, delete, or edit files depending
on the task it has been given. These changes are performed inside the sandbox, so you will need to
take action to ensure they are not lost. This could involve copying the changes back to your local machine
or committing them to a remote git branch. The process for identifying and handling file changes depends
on your choice of agent and how you have configured your sandbox - refer to your agent's documentation for
more information.
Running Cypress Tests Non-interactively​
Tests can be run for basic pass/fail measurements inside a sandbox using cypress run.
Running Cypress Tests Interactively​
An agent can run tests one at a time, monitor the execution, and query the application under test throughout using cypress tap. Doing this in a sandbox
requires running a backgrounded instance of Cypress.
Prepare the project​
When launched in a sandbox, Cypress will use the established cypress.config.js file from your project.
If a Cypress configuration has not been created yet Cypress will automatically create one when running in
--e2e mode when launched by an agent. Component testing mode (--component) requires that configuration be created before launching inside a sandbox to avoid potential mistakes with library auto-detection.
Start Cypress in the background​
Run cypress open with a browser and a testing type, and leave it running. Use
nohup so Cypress keeps running after the command that starts it returns:
nohup npx cypress open --e2e --browser chromium --project . > cypress-open.log 2>&1 &
With the above command, logging output will be written to cypress-open.log. This includes
error conditions, configuration issues, and the location of files that are created automatically. Instruct your agent
to refer to this file in the event of unexpected behavior.
When an AI agent has been detected, Cypress will automatically bypass the "welcome"
portions of the UI when --project, --browser (or set defaultBrowser in the
config), and a testing type parameter are supplied.
cypress open --detached is an alternative that waits until Cypress reports
ready before returning, instead of backgrounding right away like the nohup
form above. It doesn't keep writing to a log the way the nohup form's
redirect does: once Cypress is ready, --detached stops relaying output to
the command that started it, so a redirect on it only captures what printed
before that point, not anything that happens afterward. For the ongoing log
this page's troubleshooting steps assume, start Cypress with the nohup form
above; reach for --detached only when you don't need that log and just want
the command to block until Cypress is ready.
npx cypress open --e2e --browser chromium --project . --detached
Wait for the browser​
Once the "open" mode instance of Cypress has been launched it can be controlled and queried using cypress tap.
On initial launch it may take some time for the browser to launch; poll status until it reports a successful connection to the browser.
If the loop completes unsuccessfully read cypress-open.log for the reason.
deadline=$((SECONDS + 90))
until out=$(npx cypress tap status --json) && echo "$out" | grep -Eq '"browserAttached": *true'; do
echo "$out" | grep -Eq '"status": *"error"' && { echo "$out"; exit 1; }
[ "$SECONDS" -ge "$deadline" ] && { echo "no browser after 90 s; see cypress-open.log"; exit 1; }
sleep 1
done
Run specs and read the results​
From here the agent uses the same commands as on a local machine:
npx cypress tap run cypress/e2e/checkout.cy.ts
npx cypress tap status --json
npx cypress tap reporter --json
See Getting Started for the full loop and
Polling for a verdict for how to tell that a
run finished. The cypress-tap skill
teaches an agent this loop.
If status stays at spec not selected after you run a spec, run the spec again.
Choose a browser​
cypress tap works with Chromium-based browsers: Chrome, Chromium, Edge, and
Electron.
-
Chromium or Chrome. Pass the browser by name if it's on the
PATH, or point straight to its executable:Commandnpx cypress open --e2e --browser /usr/bin/chromium --project .Either way, Cypress runs
<path> --versionand checks the answer against what it expects for that browser, such asChromium 123.0.6312.4. Passed by name, it only checks the pattern for that one name; passed by path, it checks every pattern it knows and uses whichever one matches. So if a build isn't recognized under the name you gave it, its full path is worth trying before you give up on it — but if it isn't recognized either way, its--versionoutput doesn't match anything Cypress knows, and renaming or moving it won't change that. When Cypress can't use the browser you asked for, it writes the reason, along with the raw<path> --versionoutput, tocypress-open.log, andcypress tap statusstays atbrowser not selected. -
Electron. Electron ships with Cypress, so it works without installing a browser. Cypress prints a deprecation warning because Electron as a test browser is deprecated.
Sandboxes often come with a Chromium already installed by a browser-automation
tool. Find it with ls /opt/pw-browsers/chromium-*/chrome-linux/chrome (the
location varies by sandbox), then run <path> --version yourself to check
that it introduces itself as Chromium before pointing Cypress at it. From
there, pass the path straight to --browser, or put it on your PATH under a
name Cypress knows, like chromium, and pass that name instead — a Chromium
build like this one is recognized either way. If you try a name and Cypress
doesn't recognize it, fall back to the full path, since it's checked against
more patterns.
Once a cypress.config.* file exists, setting
defaultBrowser in it works the same
way as passing --browser, so you can set the browser once in the project
instead of on every command that starts Cypress. On the very first launch of
an unconfigured project, there is no config file yet to read defaultBrowser
from, so pass --browser instead.
Configure your sandbox​
- Claude Code on the web
- Cursor Cloud
- Other sandboxes
-
In the environment's network settings, allow the hosts in Network access.
-
In the environment's setup script, install your dependencies, which also downloads the Cypress binary:
Setup scriptnpm ciAs an alternative that lives in your repository, add a "SessionStart" hook that installs when the session runs on the web:
.claude/settings.json{"hooks": {"SessionStart": [{"hooks": [{"type": "command","command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh"}]}]}}.claude/hooks/session-start.sh#!/bin/bashset -euo pipefail[ "${CLAUDE_CODE_REMOTE:-}" = "true" ] || exit 0cd "$CLAUDE_PROJECT_DIR"npm install --no-audit --no-fund >&2npx cypress verify >&2 || { npx cypress install >&2; npx cypress verify >&2; }By default most agents will not persist the sandbox filesystem - this means Cypress and your dependencies will be re-downloaded each time which can have substantial time and bandwidth costs. Review your agent's documentation to determine if it is appropriate to cache the Cypress binary (see Environment variables) and other dependencies.
-
Claude's sandbox environments already have
xvfband a Chromium build installed, butDISPLAYis left unset and that Chromium isn't onPATH. If you have a display of your own, setDISPLAYyourself; otherwise Cypress starts an Xvfb display for you. Symlink the bundled Chromium ontoPATHaschromium, so you can refer to it by name instead of typing out the full path, then start Cypress with it. Tell the agent how to do this, or add the recipe to your agent's instructions.Commandmkdir -p ~/binln -sf "$(ls /opt/pw-browsers/chromium-*/chrome-linux/chrome | head -1)" ~/bin/chromiumPATH="$HOME/bin:$PATH" nohup npx cypress open --e2e --browser chromium --project . > cypress-open.log 2>&1 &
Cursor Cloud builds the environment from a Dockerfile and runs commands from
.cursor/environment.json.
FROM cypress/browsers:<tag>
{
"build": { "dockerfile": "Dockerfile" },
"install": "npm ci"
}
Use a
cypress/browsers image
that matches your Node.js version in place of <tag>. This image comes with
Chrome, Firefox, and Edge, but not Chromium, so pass --browser chrome when
you start Cypress. Allow the hosts in
Network access in the environment's network settings.
Any other sandbox that meets the requirements can work, including a local Docker container or an agent sandbox on your own machine. However, it may require custom configuration, dependency installation, or setup steps.
- If the sandbox restricts where processes can write or which ports they can
open, allow writes to the cache folder and connections on
127.0.0.1.
Add the recipe to your agent's instructions​
Add the steps to the file your agent reads, or install the
cypress-tap skill, which includes them:
## Run Cypress tests
Start Cypress once per session, in the background. Replace `<browser>` with
`chromium` if it is on the PATH, or with the path to a Chromium or Chrome
executable:
nohup npx cypress open --e2e --browser <browser> --project . > cypress-open.log 2>&1 &
Wait until `npx cypress tap status --json` reports a status other than
`not connected` or `browser not selected`. Stop waiting if it reports `error`
or if nothing changes after about 90 seconds, and read `cypress-open.log`.
Then run a spec with `npx cypress tap run <spec>` and poll
`npx cypress tap status --json` until `status` is `passed` or `failed` and
`startedAt` has changed. Read failures with `npx cypress tap reporter --json`.
For component testing, write the configuration, support files, and bundler
config first, and check them with `npx cypress run --component --spec <spec>`.
Environment variables​
| Name | Description |
|---|---|
CYPRESS_AGENT_MODE | Set to 1 or true to make Cypress recognize this run as an AI agent, or to 0 or false to turn that off. It only controls recognition: skipping the welcome screen still needs --project, a browser (or defaultBrowser), and a testing type. |
CYPRESS_CACHE_FOLDER | Changes the location of the Cypress binary cache |
CYPRESS_INSTALL_BINARY | Sets which Cypress binary to install: a version, URL, or local file |
Troubleshooting​
-
The binary download fails. The sandbox blocks
download.cypress.ioorcdn.cypress.io. Allow them, or use a mirror. See Network access. -
Cypress reports a missing system library. The error names the library and an install command for Debian and Ubuntu. For a library it does not recognize, it gives an
apt-file searchcommand instead;apt-fileis not installed by default, so install it first (apt-get install apt-file && apt-file update). Install the library and run the command again. -
Cypress reports that Xvfb is missing. Install the
xvfbpackage, or setDISPLAYto a display that is running. -
statusstays atnot connected. Cypress is not running yet, or it has not started loading the project. Readcypress-open.log. A project with a configuration file but no support file may also stay atnot connectedinstead of reporting an error; check thatcypress/support/e2e.jsorcypress/support/e2e.tsexists. -
statusreportserror. The project failed to load: an invalid configuration file, or (for component testing) a dev server that failed to start. Cypress prints the same error tocypress-open.log, andnpx cypress tap status --jsonincludes it undererror. After a configuration file fails to load, orsetupNodeEventsthrows, Cypress stops watching the configuration and will need to be restarted to pick up any fixes made to the configuration. -
statusstays atbrowser not selected. This can happen for two reasons. First, check that you passed--project,--browser(or setdefaultBrowser), and a testing type tocypress open; if you already did, setCYPRESS_AGENT_MODE=1, since Cypress didn't recognize the agent. Second, if you pointed--browserat a path, Cypress may not have recognized the binary at that path; read the reason incypress-open.logand see Choose a browser. -
Cypress ignores
ELECTRON_RUN_AS_NODE. Some agent environments set this variable, which makes Electron run as plain Node.js with no window.cypress openignores it and prints a warning. -
Component testing shows no session and no error. Check that the configuration, support file,
component-index.html, and bundler config (such asvite.config.*) exist, and thatsetupNodeEventsdoes not throw. Cypress does not scaffold component testing for an agent because it needs a framework and bundler to be chosen and their dependencies installed, so create these files first. To check the setup, runnpx cypress run --component --spec <spec>. -
statusreportsnot connectedfor a session that was running.cypress taprunning in a different PID namespace than Cypress, such as a separate container sharing the filesystem, can decide the session is gone. Runtapin the same container as Cypress. -
cypress openexits right away. Runnpx cypress verifyto see why the Cypress binary cannot start.
Limitations​
- The agent and Cypress have to run in the same sandbox.
- An open Cypress session with a browser uses about 2 GB of memory in a small project, and more in a larger one. Size the sandbox accordingly.
- Each new session in a sandbox that does not persist the filesystem starts with an empty Cypress binary cache. Downloading, extracting, and verifying the binary adds a delay to startup in each new sandbox instance. It is recommended to configure your sandbox to persist the binary cache directory for optimal performance.
--detachedleaves the Xvfb that Cypress started running after Cypress exits. You can find its process ID withpgrep Xvfband stop it when you're done — but only if it's the only one on the host. If another session is also running Xvfb,pgrep Xvfbturns up both with no way to tell which is yours, so skippkill Xvfbtoo: it would stop every Xvfb on the host, including the other session's. Giving each session its own sandbox, torn down once the session ends, avoids the problem entirely.cypress taphas several documented limitations to be aware of.
See also​
cypress tap: commands, polling, and examples- Cypress AI Skills: teach your agent to drive
cypress tap - Advanced installation: mirrors, proxies, and the binary cache
- Command line: the
cypress openoptions