A small Chrome / Firefox / Safari-compatible browser extension that saves the active page as a thought in TheBrain via the desktop app's local HTTP API.
It's intentionally minimal and self-contained so it can double as a reference
implementation for the local API: React + TypeScript + Vite + Tailwind, no
build-time magic beyond @crxjs/vite-plugin.
- Shows the active thought's name right in the popup, with an inline Create child / Attach toggle so you can decide per-send which mode to use — the choice is remembered.
- Splits titles like
"Apple Inc | Wikipedia"into name + label using the same separator rules the desktop clients use, and strips leading unread-count prefixes like"(19) "that sites like Gmail, YouTube, and Substack inject into the document title. - Attaches the URL to the thought with the page title as the attachment name.
- De-dupes via the local API's
by-locationendpoint: if the URL is already attached anywhere in the current brain, the extension activates that thought instead of creating a duplicate. - Optional per-send checkbox (only shown when applicable) to strip query
parameters and fragments before saving. A configurable domain
exception list (defaults:
youtube.com,youtu.be) keeps the query string intact on sites where it carries page identity. - Optional "Automatically proceed after 3 seconds" setting: the popup arms a countdown and sends without a click. Any interaction (click or key press) cancels the countdown.
- Close (×) button in the popup header to dismiss at any time.
- Connectivity, API key, and "a brain is open" are all verified the moment the popup opens, so errors surface immediately rather than after a click.
- Clear messages for the common "why did nothing happen?" cases:
- TheBrain isn't running
- API key invalid / belongs to a different user
- No brain open
- Brain is read-only
- Auto-dismisses 3 seconds after a successful save, with a shrinking progress bar so you can see it coming (and still click "Open in TheBrain" if you want to jump straight to the new thought). Clicking or pressing a key inside the popup cancels the auto-dismiss.
- Options page for updating the endpoint / API key and setting defaults for the send mode, post-save activation, auto-proceed, and the list of domains exempt from query-param trimming.
This version of the extension is published as source code so developers and tinkerers can experiment with it and adapt it to their own workflows — change the UI, tweak how titles are split, add a new send mode, whatever you like. To use it you'll build it yourself and load it into your browser. If you're not a developer, don't worry — the steps below walk through it end-to-end. You'll install one free tool (Node.js), download the code, and run three short commands.
The extension is built using Node.js, a free tool that includes a
command-line program called npm. npm downloads the small libraries this
project depends on and produces the finished extension files your browser
can load.
- Go to nodejs.org and download the LTS installer for your operating system.
- Run the installer and accept the default options.
- Confirm it worked: open a terminal window (Terminal on macOS/Linux,
PowerShell on Windows) and run:
Each should print a version number. If they don't, close and reopen the terminal window and try again.
node --version npm --version
On this GitHub page:
- Click the green Code button near the top of the file list.
- Choose Download ZIP.
- Unzip the file somewhere easy to find — your
Documentsfolder orDesktopare both fine. Once unzipped you'll have a folder named something likesend-to-thebrain-main.
If you already use git, you can clone instead:
git clone https://github.com/TheBrainTech/send-to-thebrain.gitOpen your terminal and change into the folder you just unzipped. For example, if you unzipped it onto your Desktop:
cd ~/Desktop/send-to-thebrain-main # macOS / Linux
cd %USERPROFILE%\Desktop\send-to-thebrain-main # Windows PowerShellThen run these two commands, one at a time:
npm install # downloads the libraries this project depends on
npm run build # produces the finished extension in a new "dist" folderThe first command can take a minute or two the first time — it's fetching
everything the project needs. When both finish without errors, you'll have
a dist/ folder inside your project folder. That's the extension.
The toolbar icon PNGs are committed in
public/icons/, so you don't need to regenerate them. If you changepublic/logo.svgand want to refresh the PNGs, runnpm run icons.
Chrome / Edge / Brave:
- Open
chrome://extensionsin the browser. - Turn on Developer mode (toggle in the top-right).
- Click Load unpacked and choose the
dist/folder from step 3.
Firefox: see Porting to Firefox / Safari below.
You'll see the "Send to TheBrain" icon appear in your browser toolbar. Click it and the popup will walk you through the one-time connection setup described next.
The extension talks to TheBrain's desktop app over your own computer — nothing leaves your machine. You'll copy two short values out of the desktop app and paste them into the extension once.
- Make sure TheBrain's desktop app is installed and running.
- Go to Settings → User → Local API.
- Copy the API Endpoint (e.g.
http://localhost:52341/api/) and your API Key — both have copy buttons. - In the extension popup's Setup screen (or the options page), paste both and press Test connection. If it works, you'll see your brain count.
The API key belongs to a single user — whichever user generated it.
When a new version of the code is published here, repeat steps 2 and 3
(download the ZIP again, then npm install and npm run build). Then go to
chrome://extensions and click the circular reload arrow on the "Send to
TheBrain" card. Your API key and settings are stored by the browser and will
carry over.
npm testRuns the Vitest suite, which covers:
titleSplit.test.ts— page-title →{ name, label }splitter behaviour across all the supported separators (pipe, dash, em-dash, reverse colon, non-breaking space, etc.), plus leading unread-count prefix stripping.endpoint.test.ts— normalization of the pasted API endpoint (with/without scheme, trailing slash,/apisuffix) into the base URL the client actually calls.urlTrim.test.ts— detection and stripping of query parameters and fragments used by the per-send "Remove query parameters" checkbox, plus the domain-exception matcher (exact host + subdomain).
src/
├── popup/ Popup UI — Setup flow + Send flow
├── options/ Options page — API key + behaviour
├── components/ Shared UI primitives (shadcn-flavoured)
├── api/ TheBrainLocalClient + typed errors + DTOs
├── lib/ titleSplit, sendToBrain, settings, endpoint,
│ urlTrim, browser shim
├── styles/ Tailwind entrypoint + OKLCH tokens
└── background/ Placeholder MV3 service worker
If you want to tinker with the code, npm run dev starts Vite in watch mode
so the extension rebuilds on save.
- Firefox:
manifest.jsonis already MV3-compatible. Runnpx web-ext run -s dist/after building. - Safari: Use Apple's converter:
Safari's converter wraps the extension in an Xcode project; no code changes should be needed because
xcrun safari-web-extension-converter dist/src/lib/browser.tsabstracts overchrome.*vsbrowser.*.
| Purpose | Method | Path |
|---|---|---|
| Read app state | GET | /api/app/state |
| List brains (test key) | GET | /api/brains |
| Fetch a thought (name) | GET | /api/thoughts/{brainId}/{thoughtId} |
| Find URL duplicates | GET | /api/attachments/{brainId}/by-location?location=…&type=3 |
| Create child thought | POST | /api/thoughts/{brainId} |
| Attach URL | POST | /api/attachments/{brainId}/{thoughtId}/url?url=…&name=… |
| Activate a thought | POST | /api/app/brain/{brainId}/thought/{thoughtId}/activate |
All requests send Authorization: Bearer <your-api-key>.
MIT — see LICENSE.