Run on Safari
A Safari dev session runs on the same local bridge as every other browser, so an agent can build, open, reload and read your extension there. Reach for it when you develop on macOS with Xcode and want the Safari build checked while you edit.
Quick start
With a project open, ask the agent:
Run my extension in SafariThe agent calls extension_dev with browser: "safari". The build converts your extension into a macOS app, signs it with xcodebuild, and opens it. Turn the extension on once in Safari > Settings > Extensions. From then on every save reloads it, and its background and content lines land in the session log.
To let the agent read pages too, run safaridriver --enable once and turn on Safari > Settings > Developer > "Allow remote automation" (Safari > Develop > Allow Remote Automation on older Safari).
How it works
The session needs Extension.js 4.1.21 or newer in the project. On 4.1.33 or newer the run opens the app in the background, leaves your own Safari alone, and quits only that app on stop.
The control channel is on by default, so the bridge tools work as soon as the extension is enabled: extension_storage, extension_reload, extension_open for surfaces, extension_dom_snapshot by tab id, extension_logs, and the assertions.
Safari has no CDP or RDP, and its MV3 background CSP blocks eval. So extension_eval in background fails, and extension_inspect has no Safari path. Read the background through its log lines instead.
Pages ride a safaridriver automation session. On Extension.js 4.1.32 or newer, with remote automation on, the dev session opens one and records webdriverPort and webdriverSessionId in ready.json. extension_open with url and extension_eval with context: "page" use it. extension_doctor reports it as the safari-window check.
Without that session, extension_open with url rides the bridge's navigate verb (Extension.js 4.1.29 or newer), and extension_eval in content or page needs a tab already open at the url.
Apple ships its own MCP server as safaridriver --mcp (Safari 27, or Safari Technology Preview 247 and later). It reads pages in an isolated automation window, has no extension-aware tool, and runs beside a dev session. extension_browsers reports whether your safaridriver has --mcp.
Reference
| Tool | On Safari | Extension.js |
|---|---|---|
extension_dev with browser: "safari" | Builds the app, opens it, reloads on every save, streams background and content logs | 4.1.21 or newer |
extension_logs | Works once the extension is enabled | 4.1.21 or newer |
extension_storage, extension_reload | Work over the bridge | 4.1.21 or newer |
extension_open with surface | Opens the extension's surfaces; the devtools surface is refused | 4.1.21 or newer |
extension_dom_snapshot | Works by tab id | 4.1.21 or newer |
extension_assert | content-script-injected, background-worker-booted, storage-key-present and console-errors-empty work; surface-rendered reads through the relay and can pass or fail | 4.1.21 or newer |
extension_open with url | Over the safaridriver session; without one, over the bridge's navigate verb | 4.1.32 (safaridriver), 4.1.29 (navigate) |
extension_eval with context: "page" | Over the safaridriver session; without one, the tab must already be open at the url | 4.1.32 or newer |
extension_eval with context: "content" | Needs a tab already open at the url | 4.1.21 or newer |
extension_eval with context: "background" | Fails: Safari's MV3 background CSP blocks eval | none |
extension_inspect | No Safari path: Safari has no CDP or RDP | none |
extension_doctor | Adds the safari-window check: pass, fail when the window is gone, skip with the engine's reason when none was opened | 4.1.32 or newer |
extension_start | Not supported: the framework's start and preview commands refuse Safari targets | none |
When it fails
extension_logsanswersE_LOGS_MISSING: the extension is not enabled yet, or the project runs an engine older than 4.1.21. Turn it on in Safari > Settings > Extensions, check the project'sextensionversion, then read again.extension_doctorshowssafari-windowasskip: the dev session opened no safaridriver session, and the detail carries the engine's reason. Runsafaridriver --enable, turn on remote automation, then restartextension_dev. Page eval and open by url fall back to the bridge until then.safari-windowisfail: the automation window or the driver is gone. Stop and restartextension_devwithbrowser: "safari".extension_evalinbackgroundfails: Safari's CSP blocks it. Have the background write one line on start and assertbackground-worker-booted, or readextension_logs.- The extension is enabled but a content script does nothing: Safari grants website access separately from the enable switch. Allow the site under Permissions in the same Extensions panel.
extension_startrefuses the Safari target: the framework does not runstartorpreviewfor Safari. Useextension_devfor the loop andextension_buildfor the app.
Next
- Safari guide on extension.js.org: requirements, signing and the enable step
extension_dev,extension_doctorandextension_browsers- MCP server: install and the session gates
- Publishing when the build is ready for the stores