@tamasno1/safari-cli
v0.0.6
Published
CLI tool to control Safari browser on macOS via WebDriver
Maintainers
Readme
safari-cli
A command-line tool to control Safari on macOS via WebDriver. No MCP server needed — just a standalone CLI.
Talks directly to safaridriver (built into macOS) using the W3C WebDriver protocol. Session state is persisted to ~/.safari-cli/session.json so commands work across terminal invocations.
Prerequisites
- macOS (Safari and SafariDriver are macOS-only)
- Node.js 18+
- Safari with Remote Automation enabled:
- Safari → Settings → Advanced → check "Show features for web developers"
- Develop menu → Allow Remote Automation
- Run once:
sudo safaridriver --enable
Install
# Run directly with npx (no install needed)
npx @tamasno1/safari-cli <command>
# Or install globally from npm
npm install -g @tamasno1/safari-cliQuick Start
# Start a Safari session
safari-cli start
# Navigate
safari-cli navigate https://example.com
# Page info
safari-cli info
# Title: Example Domain
# URL: https://example.com/
# Take a screenshot
safari-cli screenshot --output page.png
# Execute JavaScript
safari-cli execute 'document.title'
# Read console logs
safari-cli console
# Inspect an element
safari-cli inspect 'h1'
# Click an element
safari-cli click 'a[href]'
# Stop the session
safari-cli stopCommands
Session Management
| Command | Description |
|---------|-------------|
| start [--port PORT] | Start SafariDriver + create browser session (default port: 9515) |
| stop | Close session and kill SafariDriver |
| status | Show session status, PID, current URL |
Navigation
| Command | Description |
|---------|-------------|
| navigate <url> / go <url> | Navigate to a URL (auto-prepends https://) |
| back | Go back |
| forward | Go forward |
| refresh | Reload the page |
Page Information
| Command | Description |
|---------|-------------|
| info | Get page title and URL |
| source [-o file] | Get page source HTML |
| html [selector] [-o file] | Get outerHTML of element or full page |
| perf | Performance metrics (load times, paint, transfer size) |
Screenshots
| Command | Description |
|---------|-------------|
| screenshot [-o file] [-s selector] | Capture page or element screenshot as PNG |
Developer Console
| Command | Description |
|---------|-------------|
| console [--level LEVEL] [--inject] | Get captured console logs (LOG, WARN, ERROR, INFO, DEBUG) |
| console-clear | Clear captured console logs |
| network [--inject] | Get captured network requests (fetch + XHR) |
| network-clear | Clear captured network logs |
Note: Console/network capture works by injecting JavaScript hooks. The first call to
consoleornetworkauto-injects the hooks. Logs from before injection won't be captured. Use--injectto set up capture early.
JavaScript Execution
| Command | Description |
|---------|-------------|
| execute <script> / eval <script> | Execute JS in browser context |
| execute --async <script> | Execute async JS (call arguments[0] to resolve) |
Multi-statement scripts work: safari-cli execute 'console.log("hi"); 42'
DOM Interaction
| Command | Description |
|---------|-------------|
| inspect <selector> | Inspect element (tag, text, rect, attributes, visibility) |
| click <selector> | Click an element |
| type <selector> <text> [--clear] | Type text into input element |
| find <selector> [--text] | Find all matching elements |
| wait <selector> [-t ms] | Wait for element to appear (default: 10s) |
Selectors are CSS by default. XPath if starting with //.
Cookies
| Command | Description |
|---------|-------------|
| cookies [--json] | List all cookies |
Window Management
| Command | Description |
|---------|-------------|
| resize [-w W -h H] | Get or set window size |
| resize --maximize | Maximize window |
| resize --fullscreen | Fullscreen window |
| tabs | List open tabs/windows |
| tab <handle> | Switch to a tab by handle |
Alerts & Frames
| Command | Description |
|---------|-------------|
| alert [--accept] [--dismiss] [--text T] | Handle browser alerts/prompts |
| frame [id] | Switch iframe (no arg = top level) |
Architecture
safari-cli
├── src/
│ ├── cli.ts # Commander-based CLI with all commands
│ ├── webdriver.ts # Raw W3C WebDriver HTTP client (no selenium)
│ └── session.ts # Session state persistence (~/.safari-cli/)
├── package.json
└── tsconfig.json- Zero heavy dependencies — only
commanderfor CLI parsing - Talks to
safaridrivervia raw HTTP (fetch()) using the W3C WebDriver protocol - Session state stored in
~/.safari-cli/session.jsonso commands work across terminal invocations - Console/network logging via injected JavaScript hooks (same approach as safari-mcp-server)
Scripting Examples
# Full workflow
safari-cli start
safari-cli navigate https://news.ycombinator.com
safari-cli console --inject
safari-cli network --inject
safari-cli screenshot --output hn.png
safari-cli execute 'document.querySelectorAll(".titleline a").length'
safari-cli find '.titleline a' --text
safari-cli console
safari-cli network
safari-cli stop
# Quick page audit
safari-cli start && safari-cli go https://mysite.com
safari-cli perf
safari-cli execute 'document.querySelectorAll("img:not([alt])").length'
safari-cli stop
# Fill a form
safari-cli type '#email' '[email protected]'
safari-cli type '#password' 'secret' --clear
safari-cli click 'button[type=submit]'
safari-cli wait '.dashboard'Troubleshooting
- "Cannot connect to SafariDriver" — Run
sudo safaridriver --enableand enable Develop → Allow Remote Automation in Safari - "Session is stale" — Run
safari-cli stopthensafari-cli start - Console logs empty — Hooks are injected on first
consolecall. Logs from before that aren't captured. Useconsole --injectearly. - Only one session at a time — Safari WebDriver only supports a single session
License
MIT
