Documentation
Everything you need to know about BrowserView — from first launch to advanced automation via CLI and Runtime API.
🚀 Getting Started
Installation
BrowserView is currently available by request. To get access:
- Submit a request on the main page via the "Request Access" button
- Wait for a response with connection details and access terms
- Receive setup and launch instructions
- Install the application and open BrowserView on your Mac
First Launch
On first launch, you'll see the main canvas — this is your workspace. The app may load the last used device configuration, or you'll see a blank canvas.
Main UI elements:
- Canvas — the central area where devices are placed
- Address Bar — at the top, for entering the website URL
- Device Panel — for adding and managing devices
- Toolbar — zoom, synchronized scrolling, and other options
Quick Start in 30 Seconds
- Add several devices (e.g., iPhone, Galaxy, Desktop)
- Enter your website URL in the address bar
- Press Enter — the site loads on all devices simultaneously
- Done! You can see how your site looks on different screens
🖼️ Workspace
The canvas is an infinite workspace where all your devices are placed. You can freely pan around and zoom in or out.
Canvas Navigation
- Panning — click and drag an empty area of the canvas to move around the workspace
- Zooming — use scroll with the Ctrl key held or a pinch gesture on the trackpad to zoom in and out
- Zoom Level — the default maximum zoom is 0.5, but it can be changed
Device Layout
Devices are automatically placed on the canvas when added. BrowserView uses an intelligent layout algorithm that optimally arranges devices so they are all visible on screen.
📱 Devices
BrowserView includes over 67 built-in device profiles covering all popular phone, tablet, and desktop models.
Adding Devices
To add a device to the canvas, select it from the list of available devices. The device will appear on the canvas and immediately load the current URL.
Available Devices
- iPhone — from iPhone 7 to iPhone 16 Pro Max, all SE models
- Android — Samsung Galaxy S20–S24, Google Pixel 6–9
- Desktop — popular resolutions from 1280×1024 to 5120×2880 (iMac 5K)
Device Rotation
Any mobile device can be rotated to landscape (horizontal) orientation. This is useful for checking site responsiveness when the phone is turned.
Detach into Separate Window
You can detach a device from the canvas and work with it in a separate floating window. This is especially handy with multiple monitors — place the phone on one screen and the desktop on another.
Custom Sizes
In addition to built-in profiles, you can set a custom resolution in the "Desktop WidthxHeight" format (e.g., "Desktop 1920x1080").
🔄 Synchronized Scrolling
Synchronized scrolling is one of BrowserView's key features. When enabled, scrolling on one device automatically scrolls all other devices to the same position.
How to Enable
Click the synchronized scrolling button on the toolbar or use the hotkey. When active, the indicator will light up.
How It Works
When you scroll a page on any device, all other devices scroll to the same relative position. This lets you instantly check how a specific content block looks on all screens.
⚡ Two Rendering Engines
BrowserView is the only tool that uses two browser engines at once: WebKit and Chromium. This gives you an accurate picture of how your site looks across different browsers.
WebKit
This is the Safari engine — the browser installed on every iPhone and iPad. When you view a site on a virtual iPhone in BrowserView, it renders exactly as real Safari users will see it. It's the native macOS engine, so it runs as fast and accurately as possible.
Chromium (CEF)
This is the engine behind Chrome, Edge, Opera, and most Android browsers. BrowserView uses Chromium Embedded Framework to render Android and desktop devices. You see exactly what Chrome users will see.
Why Two Engines?
WebKit and Chromium handle CSS, fonts, and JavaScript differently. A bug absent in Chrome may break layout in Safari — and vice versa. With two engines, you catch the issue before your users do.
🛠️ DevTools
BrowserView provides developer tools for each device. Depending on the engine, you get the corresponding DevTools.
Safari Web Inspector (WebKit)
For WebKit devices (iPhone, iPad), Safari Web Inspector opens — a powerful tool for inspecting DOM, CSS, network requests, and performance. It launches as a separate system Web Inspector window.
Chrome DevTools (Chromium)
For Chromium devices (Android, Desktop), Chrome DevTools open — the developer tools familiar to every web developer with Elements, Console, Network tabs, and more.
How to Open
Select a device and use the context menu or hotkey to open DevTools. The tools open for the specific selected device — you can debug the exact viewport you're interested in.
💾 Presets
Presets let you save and load device configurations. This is convenient if you regularly work with a specific set of devices.
Saving a Preset
Set up the canvas with the devices, URL, and settings you need. Save the configuration as a JSON preset file that you can load later.
Loading a Preset
Load a previously saved preset, and all devices, URLs, and settings will be restored automatically. This is especially handy for switching between projects.
Usage Examples
- "Mobile" — iPhone 16 Pro, Galaxy S24, Pixel 9 for mobile testing
- "Full Set" — several mobile + tablet + desktop for full coverage
- "Client X" — specific devices used by the client
📸 Screenshots
BrowserView allows you to take screenshots of individual devices. This is useful for documentation, client presentations, or visual regression testing.
How to Take a Screenshot
You can capture a screenshot of a specific device — WebKit or Chromium. The screenshot is saved as a PNG file to a location you specify. For automation, use command-line arguments (described in the "For Developers" section).
⌨️ Hotkeys
Hotkeys speed up your workflow. Here are the main shortcuts:
| Shortcut | Action |
|---|---|
| ⌘ + R | Reload all devices |
| ⌘ + L | Focus address bar |
| ⌘ + + | Zoom in |
| ⌘ + − | Zoom out |
| ⌘ + 0 | Reset zoom |
| ⌘ + , | Open settings |
💳 Subscription
Trial Period
Trial access and onboarding terms are discussed when reviewing your request. We'll include available options and next steps for activation in our response.
Subscribing
Access to the application is currently provided by request. After approval, you'll receive instructions for setup and activation.
Managing Your Subscription
- Access status — use the form on the feedback page
- Changing terms — to change your plan or renew, submit a request via the feedback form
- Reactivation — if you reinstalled the app, submit a request via the feedback form
Command-Line Arguments
Launch BrowserView with arguments to configure devices, URLs, and behavior. All arguments can be combined.
Device Management
# Launch with empty canvas (ignore saved state)
--empty
# Add devices to the main canvas
--device="iPhone 16 Pro"
--device="Galaxy S24"
--device="Desktop 1920x1080"
# Open device in a separate window
--detach="iPhone 15"
# Rotate device to landscape orientation
--rotate="iPhone 16 Pro"
# Multiple devices at once
--device="iPhone 16" --device="Pixel 9" --device="Galaxy S24"
Navigation
# Load URL (https:// added automatically if no scheme)
--url=https://example.com
--url=example.com
--url=http://localhost:3000
--url=file:///path/to/index.html
Display Options
# Set maximum zoom level (0.1 to 2.0, default: 0.5)
--zoom=0.8
# Enable synchronized scrolling for all devices
--scroll-sync
# Watch directory and auto-reload on changes
--watch-dir=/path/to/your/project
Presets
# Load a saved preset configuration
--preset=/path/to/my-preset.json
Screenshots and Testing
# Capture screenshot of a WebKit device
--webkit-view-screenshot-path=/path/to/output.png
# Capture screenshot of a CEF (Chromium) device
--cef-screenshot-path=/path/to/output.png
# Run test scroll on a device
--test-touch-scroll="iPhone 16 Pro"
# Log processed arguments to a file
--args-log-path=/path/to/args.log
# Write JSON layout metrics on each pass
--layout-log-path=/path/to/layout.json
Full Example
# Launch with 3 devices, URL, synchronized scrolling, and file watching
BrowserView --empty \
--device="iPhone 16 Pro" \
--device="Galaxy S24" \
--device="Desktop 1920x1080" \
--url=http://localhost:3000 \
--watch-dir=./src \
--scroll-sync
Runtime API (Distributed Notifications)
Control BrowserView at runtime via macOS Distributed Notifications. This lets external scripts and AI agents manipulate the application in real time.
Available Notifications
| Notification Name | Object (payload) | Description |
|---|---|---|
com.viewportstudio.addDevice |
Device name | Add a device to the canvas |
com.viewportstudio.detachDevice |
Device name | Detach a device into a floating window |
com.viewportstudio.navigateURL |
URL string | Navigate to URL on all devices |
com.viewportstudio.openDevTools |
Device name | Open DevTools for a device |
com.viewportstudio.highlightElement |
deviceName|cssSelector |
Highlight a DOM element in a device |
com.viewportstudio.lowerDetachedWindows |
(any) | Lower floating windows to normal level |
Sending from Swift
import Foundation
DistributedNotificationCenter.default().post(
name: NSNotification.Name("com.viewportstudio.addDevice"),
object: "iPhone 16 Pro"
)
Sending from Shell
# Add a device
swift -e 'import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name("com.viewportstudio.addDevice"), object: "iPhone 16 Pro"); RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))'
# Navigate to URL
swift -e 'import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name("com.viewportstudio.navigateURL"), object: "https://example.com"); RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))'
# Open DevTools
swift -e 'import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name("com.viewportstudio.openDevTools"), object: "Galaxy S24"); RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))'
Sending from Python
import subprocess
def send_notification(name, value):
script = f'''
import Foundation
DistributedNotificationCenter.default().post(
name: NSNotification.Name("{name}"),
object: "{value}"
)
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
'''
subprocess.run(['swift', '-e', script])
# Usage
send_notification('com.viewportstudio.addDevice', 'iPhone 16 Pro')
send_notification('com.viewportstudio.navigateURL', 'https://example.com')
Sending from Node.js
const { execSync } = require('child_process');
function sendNotification(name, value) {
const script = `
import Foundation
DistributedNotificationCenter.default().post(
name: NSNotification.Name("${name}"),
object: "${value}"
)
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
`;
execSync(`swift -e '${script}'`);
}
// Usage
sendNotification('com.viewportstudio.addDevice', 'iPhone 16 Pro');
sendNotification('com.viewportstudio.navigateURL', 'https://example.com');
Automation Examples
Screenshot Automation
#!/bin/bash
# Capture screenshots of a site on multiple devices
APP="/Applications/BrowserView.app/Contents/MacOS/BrowserView"
"$APP" --empty \
--device="iPhone 16 Pro" \
--device="Galaxy S24" \
--device="Desktop 1920x1080" \
--url="https://your-site.com" \
--webkit-view-screenshot-path="./iphone.png" \
--cef-screenshot-path="./android.png"
Recording an Interactive Demo
#!/bin/bash
# Automated demo: adding devices one by one with delays
BrowserView --empty --url="https://your-site.com" &
sleep 3
# Sequential device addition
for device in "iPhone 16 Pro" "Galaxy S24" "Desktop 1920x1080"; do
swift -e "import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name(\"com.viewportstudio.addDevice\"), object: \"$device\"); RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))"
sleep 2
done
# Opening DevTools for one device
swift -e 'import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name("com.viewportstudio.openDevTools"), object: "Galaxy S24"); RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))'
For AI Agents
BrowserView is designed for full control by AI coding agents such as Claude, GPT, and others. Here's how agents can interact with the application:
Capabilities
- Launch with configuration — Start the app with specific devices, URLs, and settings via CLI
- Runtime control — Add/remove devices, navigate, open DevTools while the app is running
- Screenshot capture — Capture device screenshots for visual verification
- Layout metrics — Get JSON output of layout calculations for verification
- File watching — Auto-reload on code changes
Agent Integration Pattern
# 1. Launch BrowserView with initial configuration
BrowserView --empty \
--device="iPhone 16 Pro" \
--url="http://localhost:3000" \
--watch-dir=./src
# 2. Agent makes code changes...
# (App auto-reloads via watch-dir)
# 3. Agent adds more devices for testing
swift -e 'import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name("com.viewportstudio.addDevice"), object: "Galaxy S24")'
# 4. Agent captures a screenshot for verification
# (Use CLI screenshot arguments or screen capture tools)
# 5. Agent opens DevTools for debugging
swift -e 'import Foundation; DistributedNotificationCenter.default().post(name: NSNotification.Name("com.viewportstudio.openDevTools"), object: "iPhone 16 Pro")'
Supported Devices
Device names are case-insensitive. Available devices include:
- iPhone — iPhone 7 through iPhone 16 Pro Max, SE models
- Android — Galaxy S20-S24 series, Pixel 6-9 series
- Desktop — Common resolutions from 1280x1024 to 5120x2880
CI/CD Integration
BrowserView can be integrated into continuous integration workflows for automated visual testing.
GitHub Actions
# .github/workflows/visual-test.yml
name: Visual Regression Test
on: [push, pull_request]
jobs:
visual-test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Start dev server
run: npm run dev &
- name: Wait for server
run: sleep 5
- name: Run BrowserView
run: |
"/Applications/BrowserView.app/Contents/MacOS/BrowserView" \
--empty \
--device="iPhone 16 Pro" \
--device="Desktop 1920x1080" \
--url="http://localhost:3000" \
--webkit-view-screenshot-path="./screenshots/iphone.png" \
--cef-screenshot-path="./screenshots/desktop.png" \
--layout-log-path="./layout.json"
- name: Upload screenshots
uses: actions/upload-artifact@v4
with:
name: screenshots
path: screenshots/
Shell Script for CI
#!/bin/bash
# visual-regression.sh — visual regression testing
set -e
APP="/Applications/BrowserView.app/Contents/MacOS/BrowserView"
SCREENSHOTS_DIR="./screenshots"
mkdir -p "$SCREENSHOTS_DIR"
# Start dev server
npm run dev &
DEV_PID=$!
sleep 5
# Capture screenshots
"$APP" --empty \
--device="iPhone 16 Pro" \
--device="Desktop 1920x1080" \
--url="http://localhost:3000" \
--webkit-view-screenshot-path="$SCREENSHOTS_DIR/iphone.png" \
--cef-screenshot-path="$SCREENSHOTS_DIR/desktop.png" \
--layout-log-path="$SCREENSHOTS_DIR/layout.json"
# Stop dev server
kill $DEV_PID
echo "✅ Screenshots saved to $SCREENSHOTS_DIR"
Fastlane
# fastlane/Fastfile
lane :visual_test do
sh("npm run dev &")
sleep(5)
viewport_app = "/Applications/BrowserView.app/Contents/MacOS/BrowserView"
sh("#{viewport_app} --empty " \
"--device='iPhone 16 Pro' " \
"--device='Desktop 1920x1080' " \
"--url='http://localhost:3000' " \
"--webkit-view-screenshot-path='./screenshots/iphone.png' " \
"--cef-screenshot-path='./screenshots/desktop.png'")
sh("pkill -f 'npm run dev' || true")
end
Layout Log
When using the --layout-log-path argument, BrowserView writes a JSON file with layout metrics on each pass. This is useful for automated testing and verification.
File Format
{
"timestamp": "2025-01-15T10:30:00Z",
"devices": [
{
"name": "iPhone 16 Pro",
"engine": "webkit",
"width": 393,
"height": 852,
"scale": 3,
"rotated": false,
"position": { "x": 0, "y": 0 }
},
{
"name": "Desktop 1920x1080",
"engine": "cef",
"width": 1920,
"height": 1080,
"scale": 1,
"rotated": false,
"position": { "x": 420, "y": 0 }
}
],
"canvas": {
"zoom": 0.5,
"scrollSync": true
}
}
Usage for Tests
#!/bin/bash
# Verify that all devices loaded correctly
LAYOUT=$(cat layout.json)
# Check device count
DEVICE_COUNT=$(echo "$LAYOUT" | python3 -c "import sys,json; print(len(json.load(sys.stdin)['devices']))")
if [ "$DEVICE_COUNT" -ne 3 ]; then
echo "❌ Expected 3 devices, got $DEVICE_COUNT"
exit 1
fi
echo "✅ Layout log: $DEVICE_COUNT devices loaded"
# Python: parse layout log
import json
with open('layout.json') as f:
layout = json.load(f)
for device in layout['devices']:
print(f"{device['name']}: {device['width']}x{device['height']} ({device['engine']})")
# Verify all devices are present
expected = {"iPhone 16 Pro", "Galaxy S24", "Desktop 1920x1080"}
actual = {d['name'] for d in layout['devices']}
assert expected == actual, f"Missing devices: {expected - actual}"
Troubleshooting
Application Won't Start
Make sure you're using a supported version of macOS. Check the system requirements in the instructions you received. Try restarting your Mac and launching the app again.
localhost Not Loading
Make sure your dev server is actually running and listening on the specified port. Try opening the same URL in a regular browser. If the server listens on 127.0.0.1, try using localhost and vice versa.
WebKit and Chromium Show Different Results
This is normal and expected! That's the whole point of two engines — you discover cross-browser differences. Check CSS properties that are interpreted differently by engines: -webkit- prefixes, flexbox/grid nuances, font rendering.
Synchronized Scrolling is Inaccurate
Synchronized scrolling works in proportional mode. If pages have different content heights on different devices, the scroll position will be approximate. This is normal behavior.
Screenshots Not Saving
Check that the file path is correct and the directory exists. Make sure the app has write permissions to the specified directory. When using relative paths, they resolve from the current working directory.
CLI Arguments Not Working
# Make sure you're using the full path to the executable:
"/Applications/BrowserView.app/Contents/MacOS/BrowserView" --empty --device="iPhone 16 Pro"
# Or add an alias to ~/.zshrc:
alias viewport='"/Applications/BrowserView.app/Contents/MacOS/BrowserView"'
# For argument debugging, use the log:
BrowserView --args-log-path=/tmp/viewport-args.log --device="iPhone 16 Pro"
cat /tmp/viewport-args.log
Distributed Notifications Not Delivered
# Check that the application is running:
pgrep -f "BrowserView" || echo "Application is not running!"
# Make sure RunLoop has time to send the notification:
swift -e '
import Foundation
DistributedNotificationCenter.default().post(
name: NSNotification.Name("com.viewportstudio.addDevice"),
object: "iPhone 16 Pro"
)
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.5))
'
# Note: a 0.5s delay (instead of 0.1s) may help with unstable delivery