Convert the current Safari tab to clean Markdown with one click, powered by Codex.
I kept doing the same thing: reading something in Safari, wanting it as Markdown for my notes or for LLM context, and copy-pasting messy HTML. One click should get me clean, well-structured Markdown. SafariMarkdown reads the page via AppleScript, sends it to a local Codex server, and streams back the result in real time.
- macOS 26+
- Safari with "Allow JavaScript from Apple Events" enabled (Safari > Settings > Advanced > check "Show features for web developers", then Developer menu > Allow JavaScript from Apple Events)
- Codex app server running locally:
codex-app-server --listen ws://127.0.0.1:8080
brew install --cask scasella/tap/safarimarkdowngit clone https://github.com/scasella/SafariMarkdown.git
cd SafariMarkdown
bash build.sh
open SafariMarkdown.app- Start the Codex app server:
codex-app-server --listen ws://127.0.0.1:8080 - Open any web page in Safari
- Click the MD icon in your menu bar
- Click Convert Current Page
- Watch Markdown stream in real-time
- Click Copy to copy to clipboard
- Reads the current Safari tab's URL, title, and body text via AppleScript
- Connects to the local Codex app server over WebSocket
- Creates an ephemeral thread with
gpt-5.3-codex-sparkat medium effort - Sends the page content with instructions to extract main content and format as Markdown
- Streams the response in real-time with a monospaced text display
- Disconnects when done — no persistent connections
Convert a blog post: Open any blog post in Safari → click MD → click Convert → get clean Markdown with proper headings, code blocks, and links.
Convert documentation: Open API docs or library docs → convert → paste into your notes or feed to an LLM as context.
Convert a news article: Open a news article → convert → get just the article content without ads, nav, comments, and sidebars.
Partial copy during streaming: Click Copy at any time during conversion to grab whatever has been generated so far.
Cancel and retry: Click Cancel during conversion, or Try Again on error.
| Icon | State |
|---|---|
MD (doc.richtext) |
Idle — ready to convert |
... (ellipsis) |
Reading page or connecting |
↻ (arrows) |
Converting — streaming in progress |
✓ (checkmark) |
Done — conversion complete |
⚠ (warning) |
Error — see popover for details |
"Safari is not running" — Open Safari and navigate to a page first.
"Could not read page content" — Enable JavaScript from Apple Events: Safari > Settings > Advanced > Show features for web developers > then Developer menu > Allow JavaScript from Apple Events.
"Could not connect to Codex server" — Start the server:
codex-app-server --listen ws://127.0.0.1:8080
"Page content is empty" — The page may be a PDF, image, or still loading. Wait for it to finish loading and try again.
Content is truncated — Pages over 60,000 characters are truncated to stay within model context limits. The truncation point is noted in the output.
Single-file SwiftUI app (~550 lines):
RawWebSocket— raw TCP WebSocket client (avoidsSec-WebSocket-Extensionsrejection)SafariReader— NSAppleScript wrapper for Safari tab accessMarkdownConverter— @Observable state machine managing the full conversion lifecycleContentView— MenuBarExtra with state-driven sub-views
MIT
