periscope
An agentic headless browser that websites see as Safari.
github.com/oskar-szulc/periscope
In short: periscope is an open-source command-line browser for AI agents on macOS. It runs Safari’s WebKit engine so sites see a normal Safari, keeps pages open between commands, and returns a page as markdown, structured JSON, a link list or a screenshot. Agents drive it from the shell or over MCP.
$ periscope navigate https://books.toscrape.com/ --session demo Navigated to: All products | Books to Scrape - Sandbox URL: https://books.toscrape.com/ Status: 200 · Text: 1,809 chars · HTML: 50,989 chars $ periscope state --session demo --match Tipping Actions (1): @58 … > article > h3 > a a "Tipping the Velvet" $ periscope click @58 --session demo Navigated to: Tipping the Velvet | Books to Scrape - Sandbox Status: 200 · Text: 1,574 chars · HTML: 10,672 chars
periscope runs WebKit, the engine that ships with macOS and powers Safari. An agent drives it from the shell or over MCP. Pages stay open between commands, so an agent can load a page, read it, click something and come back to the same page a minute later.
Reading a page
Five ways to read it.
One page, five views. Scroll through them.
01 · text
The content as markdown.
For reading an article or a post. Images are left out, and --no-links drops the link URLs, which on a busy page are most of the size.
02 · state
What you can do next.
Headings, the start of the content, and every clickable element with a selector and a number. click @58 clicks the 58th one. The numbers expire when the page navigates, so an old number can’t point at an element on a different page.
03 · extract
The page’s records, as JSON.
Jobs, products, search results, table rows. No selectors to write and no model to call. It also returns the page’s structured data and the link to the next page.
04 · links
Every link, as an absolute URL.
Filter them with a regular expression to collect the pages worth visiting next.
05 · screenshot
The page as it looks.
A PNG of the viewport, or the whole page with --full. It waits for images and fonts to load first.
extract
It finds the records by itself.
It looks for siblings that share a tag and class, pools them across the page, and picks the group with the most substantial text. Nothing is written for each site.
It also reads the schema.org data a page publishes. A job page’s JobPosting has the salary as numbers, which is cleaner than anything scraped from the layout.
Fingerprint
Sites see Safari.
The user agent is Safari’s, taken from the installed Safari. Pages report themselves as visible, animation frames run, and type sends real key events.
When a site does put up a bot check, periscope says so. Google’s CAPTCHA and “verifying your request” pages, DuckDuckGo’s challenge and Cloudflare’s “Just a moment” all exit with code 5 instead of passing for content. --wait-challenge 20 gives a check that clears itself time to finish.
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5.2 Safari/605.1.15 $ periscope navigate https://example.com/… Error: Blocked by cloudflare-challenge at https://example.com/… $ echo $? 5
Sessions
Pages stay open.
A background daemon holds one live WebKit page per named session. The command line sends each command over a unix socket and prints the reply. Nothing reloads between commands, so logins, single-page-app routes and scroll position survive. login and show put the window on screen so a person can sign in or solve a CAPTCHA, then hand it back.
periscope text --session demoan eval on an open page
text of an open page
loading a new page
For agents
Install it where your agent is.
brew install oskar-szulc/tap/periscope/plugin marketplace add oskar-szulc/periscopenpx skills add oskar-szulc/periscopeperiscope mcp, listed in the MCP Registry as io.github.oskar-szulc/periscopeperiscope docs prints the full reference for an agent that already has it.
periscope is open source under the MIT licence: github.com/oskar-szulc/periscope

Leave a Reply