Browse the docs

Safari and Chrome

Connect your browser to Switchboard, then start macros from pages, change pages, and let page buttons run macros and get the result.

Keyboard Maestro: Execute JavaScript in Front Browser, Browser Trigger

Switchboard has a small extension for Safari and for Chrome (and Arc, Brave, Edge and Vivaldi). It keeps a two-way connection open to Switchboard, so a page can start macros and macros can run inside a page.

Connect a browser #

Open Settings ▸ Browsers. Each browser has one row with its state and one button for the next step.

  • Safari. The extension is inside Switchboard.app. The button opens Safari ▸ Settings ▸ Extensions: turn on Switchboard and allow it on all websites.

  • Chrome and the others. Chrome lets people add extensions from the Web Store; until Switchboard is listed there, load it yourself: the button reveals the extension's folder and opens chrome://extensions. Turn on Developer mode (Chrome switches an unpacked extension off again if you turn it off), choose Load unpacked and pick the folder.

  • Allow User Scripts. To run your own JavaScript in pages, open the extension's Details in chrome://extensions and turn on Allow User Scripts. Without it, CSS, HTML, triggers, the page buttons and everything else work, and JavaScript runs through AppleScript a moment after the page loads.

Switchboard says Connected when the extension has reached it.

Triggers #

A trigger is something that happened in a page, a tab or the browser: A page loads, changes or closes (a page loads, changes address, comes to the front, closes or fails), A tab opens, plays sound or moves, An element appears on a page (appears, disappears, changes), You click an element on a page, A form is submitted, You select text on a page, A page sends an event (a page says something), You choose a right-click menu item (a right-click item), A download starts or finishes, A page makes a request and A browser connects or disconnects.

The extension only reports what a macro asked about, so the rest of your browsing never reaches Switchboard and writes nothing in the Activity window.

Pages #

Put CSS, HTML and JavaScript into a page with Put CSS, HTML or JavaScript in the page. A macro that starts with browser.page on loading and then injects CSS and HTML with no variables is applied by the browser itself before the page paints, with Switchboard off: dark mode for one site, with no flash. The editor marks that run Runs instantly in the page.

Injected code gets a switchboard object:

switchboard.emit("saved", { id: 42 })          // starts macros with a browser.event trigger
await switchboard.run("Save to list", { url })  // runs a macro and returns its result
switchboard.on("status", fn)                    // receives browser.send pushes
await switchboard.vars.get("count")             // shared variables

A macro a page calls also gets url (the page's address), tabId and browser as inputs when it declares them (add them under the macro's inputs), so a step with tab: trigger works on the page that called. In HTML, data-switchboard-run="Macro" runs a macro (its input from data-input or the nearest form), data-switchboard-emit="name" fires an event and data-switchboard-bind="variable" keeps an element in step with a shared variable.

Scraping #

Scrape a page into rows takes every item on a page as a row: fields with numbers and dates read properly, several pages, from your own browser or from a plain fetch with no browser open. The editor writes the recipe for you: Pick Rows in Browser (click one item and its siblings light up; click inside it to name a column; click the pager's Next), Use Selection for whatever you have selected, and a live Preview table of the rows. Write Fields with AI takes "name, price, rating" and writes the columns from the page, checked against the real rows before you apply it. Save rows to a file or the clipboard puts the rows in a CSV, Markdown, JSON or JSON Lines file, grows one file night after night without duplicates, or puts a table on the clipboard that pastes into Numbers.

Right-click in a page and the Switchboard menu has Scrape this list… and Watch this for changes…; each makes a finished macro you can open and change. In the palette, Watch This Page… does the same for the front tab.

A web page changes watches a page on a schedule: a price that drops, a product back in stock, a new listing, a site that went down. It needs no open tab. When a scrape that used to find rows finds none, the page's layout changed: Activity offers Repair Fields with AI, which rewrites the columns from the page it kept and shows you the rows first.

Fetches look like a browser. Many sites refuse a plain script's request before they send anything. A fetch here presents the handshake and headers of a current Chrome or Safari, and it can carry a saved sign-in: in Library ▸ Sign-ins, save one from the browser you are signed in with (it reads that site's cookies, after you allow it once), sign in to a background tab, or paste a cURL command or Cookie: header from the browser's developer tools. The cookies are kept in your Mac's Keychain, used only for the sites they were saved for, and never appear in a macro, a trace or a shared file; a macro holds only the sign-in's name (signIn: "GitHub"). When a site signs you out, the step says signInExpired and the sign-in shows Expired with Refresh.

What it does not do. Switchboard solves no CAPTCHA or challenge, runs no stealth browser and rotates no proxies. A site that answers with a challenge fails the step (challenge cloudflare), and via: tab reads the page in your own browser instead. What a site allows is your call; keep the pace polite (the default is at least a quarter second per site).

Safety #

  • Only code Switchboard injected gets the switchboard object. The site's own scripts can't take it.

  • switchboard.run only runs macros you switched on under Callable from pages in the macro's settings, and only from the pages listed there (by default the pages of the macro's own browser triggers). Anything else is refused and appears in Activity as "not fired".

  • A site's own scripts can only start browser.event macros from addresses listed in that trigger's allowPageOrigins. By default none.

  • Private windows are off until you allow them in Settings ▸ Browsers (the browser needs its own permission too).

  • Field values, HTML and event data kept in a trace follow the same redaction rules as webhook bodies. Passwords are never read from forms.

When something doesn't work #

  • Not connected: quit and reopen the browser; check the row in Settings ▸ Browsers.

  • Chrome switched the extension off: turn Developer mode back on in chrome://extensions.

  • A step says Allow User Scripts: turn it on, as above.

  • A page does nothing: chrome:// pages, the Chrome Web Store and Safari's start page don't allow extensions.