Looking for Python Actors? The same one-link browser debugging exists for Python, built on debugpy plus a served DAP frontend — see
python/README.md.
Drop-in remote debugging for any Apify Node/TS Actor with a one-line Dockerfile change. It launches your Actor under the Node inspector and serves a full Chrome DevTools UI over the run's container URL — so you open one link in your own browser and debug. No wstunnel, no local setup, no rebuild of your source, and no browser in the Actor.
# Get the package
RUN npm install actor-debugger
# pause on the first line until a debugger attaches (for short-lived Actors):
CMD ["npx", "actor-debugger", "--brk"]
# or point at a specific entry:
CMD ["npx", "actor-debugger", "dist/main.js"]- It resolves your Actor's entrypoint (see detection order below) and launches it as
node --inspect=127.0.0.1:9229 <entry>— so the inspector is on your code, in its own process, exactly as it normally runs. - It runs one HTTP server on
ACTOR_WEB_SERVER_PORTthat:- serves the Chrome DevTools frontend (static files) so your local browser opens it — no Chrome, Xvfb, or VNC in the Actor;
- proxies the CDP WebSocket to the inspector, rewriting
Hostto a loopback IP and droppingOrigin. Node's inspector rejects DNS-name hosts (anti-DNS-rebinding), so this rewrite is what lets a browser reach it over<run>.runs.apify.net.
- The run log prints one URL. Open it in your browser → real DevTools attached to your Actor.
The DevTools frontend comes from chii (MIT), which ships
a prebuilt Chrome DevTools frontend. The chrome-devtools-frontend npm package is unbuilt
TypeScript source (needs Chromium's GN/ninja toolchain to compile), so it can't be served as-is —
chii's build is the same frontend, ready to serve.
Running the Actor through npx actor-debugger is the switch — debugging is on whenever the
CMD line above is in place. To turn it off, revert the CMD to the Actor's normal entrypoint
(e.g. CMD ["npm", "start"]) and rebuild. Pass --brk to pause on the first line until a
debugger attaches — useful for Actors that would otherwise finish before you connect.
Open the URL the run log prints, in your own browser:
https://<run>.runs.apify.net/devtools/js_app.html?wss=<run>.runs.apify.net/<uuid>
That page is Chrome DevTools; it connects to your Actor over the container URL. Set breakpoints
in your sources (via source maps), step, inspect — no devtools:// URL, no local install.
Prefer the raw channel? npx wscat -c "wss://<run>.runs.apify.net/<uuid>", or point
Playwright/Puppeteer connectOverCDP at that wss URL.
The WebSocket scheme in the printed URL follows the container URL's scheme: wss on the platform
(https container URLs), plain ws on a local Apify dev stack (http on localhost). Always use the
URL exactly as printed in the run log.
A remote DevTools frontend can never fetch file:// URLs from the container, so external
.js.map files — the standard "sourceMap": true tsc output — are unreachable to it, and
DevTools would fall back to the generated JS ("Source map failed to load"). The debugger fixes
this itself at startup: it scans the compiled output, reads each external .map from the
container's disk, embeds the original TS text into it (sourcesContent, read from the .ts
files in the image), and rewrites the reference into an inline data: URL. Any tsc setup that
emits source maps at all (sourceMap or inlineSourceMap) therefore just works — no tsconfig
changes needed.
The one unrecoverable case is a build with no source maps: then the run log prints a hint to
compile with "sourceMap": true. If the .ts files aren't in the image (a multi-stage build
copying only dist/), mappings still inline but sources can't be shown — the log says so; COPY
your src/ into the final stage to fix it.
- An explicit path argument, if given.
- The file in
package.jsonscripts.start(e.g.node dist/main.js→dist/main.js). package.jsonmain.- Conventional paths:
dist/main.js,dist/index.js,build/main.js,src/main.js,main.js,index.js.
The debug endpoint is unauthenticated — anyone who reaches the container URL and the run's
uuid can execute code in your run (and read its env, including APIFY_TOKEN). Keep the
actor-debugger CMD only in builds you are actively debugging, prefer a restricted run/token,
never ship it in a published Actor, and gate the endpoint (owner-only) before any non-prototype
use.
Publishing to npm is done by
.github/workflows/publish.yml,
started manually from the Actions tab. It publishes via npm Trusted Publishing (OIDC) — no npm
token or repository secret, and provenance attestations are generated automatically. The trusted
publisher configured on npmjs.com is: repository apify/actor-debugger, workflow publish.yml
(the workflow file name must stay exactly that). To cut a release:
-
Bump the version in
javascript/package.jsonin a PR and merge it tomaster:cd javascript npm version patch --no-git-tag-version # or minor / major
-
Open Actions → Publish to npm → Run workflow on
master.
The workflow refuses to run on any other branch, or if that version is already on npm or its
vX.Y.Z tag already exists. It then syntax-checks the sources, smoke-tests both modes (disabled
pass-through and the debug server with /json/list + DevTools frontend), checks the pack contents,
runs npm publish from javascript/, and finally pushes the vX.Y.Z tag and creates the GitHub
release with generated notes. Do not create tags or releases by hand.
- Depends on
chiifor the prebuilt DevTools frontend (~16 MB of static assets, no runtime browser). - Pure Node otherwise — works on any
apify/actor-node*base image, no Xvfb / Chrome / apt.