Otter is a self-hosted bookmark manager made with Next.js and Supabase with Mastodon integration.
Features • Getting started • Docs • Ecosystem
- Private bookmarking app with search, tagging and filtering
- Dark/light colour modes
- Mastodon integration - backup of your own toots as well as your favourite toots
- Raycast extension to search your bookmarks, view recent bookmarks and create new ones
- Chrome extension for easy bookmarking
- Bookmarklet
Feed (dark mode) |
Feed (light mode) |
---|---|
New bookmark |
Search |
Feed (showing tags sidebar) |
Toots feed |
- pnpm - install with
npm i -g pnpm
- Vercel account and the Vercel CLI - install with
npm i -g vercel
- Supabase account and the Supabase CLI - install with
npm i -g supabase
- Cloudflare account (optional) - used for the page scraper and Mastodon to Supabase worker
- Fork this repo
- Go to database.new and create a new Supabase project. You will need the project ID (found in the project settings page) and the the database password for the next step.
- Link your Supabase project to your local dev environment:
pnpm supabase:link
- Seed your database with
pnpm supabase:setup
- Install npm dependencies with pnpm:
pnpm install
- Create a new project on vercel and setup env vars (see below)
- To allow signups, set the value of
ALLOW_SIGNUP
in./src/constants.ts
totrue
- Run the app locally using
pnpm dev
- Visit
http://localhost:5678
and create an account
Set up the following env vars using either the Vercel CLI or through the Vercel project settings. Once they are added run vc env pull
to pull them down to your local dev environment.
# Find these in your Supabase project settings > API
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_KEY=your-service-key # only needed for testing APIs using the `*.rest` files
PERSONAL_MASTODON_ACCESS_TOKEN=your-personal-app-mastodon-access-token
BOT_MASTODON_ACCESS_TOKEN=your-bot-app-mastodon-access-token
OTTER_API_TOKEN=your-otter-api-token
Interactive API docs can be found in the various *.rest
files in the /app/api
directory.
POST /api/new
- create new item in OtterGET /api/new?url=https://example.com
- quick create new item in Otter. Pass in aurl
query param and it will create a new item with that URL and includes its metadata tooGET /api/bookmarks
- returns all bookmarks
GET /api/search?searchTerm=zander
- search bookmarkPOST /api/toot
- A PostgreSQL trigger function calls this endpoint anytime a bookmark is created or edited which then creates a new toot on two of my Mastodon accounts (@[email protected] & @[email protected]). It only sends a toot if the bookmark has thepublic
column set totrue
.
Otter has the ability to auto-toot to 2 Mastodon accounts when a new bookmark is created or edited. This is done via a PostgreSQL trigger function that calls the /api/toot
endpoint.
The trigger function below uses an environment variable in the Authorization
header to ensure only the owner of the Otter instance can call the endpoint.
create trigger "toot-otter-items"
after insert
or
update on bookmarks for each row
execute function supabase_functions.http_request (
'https://{your-otter-instance}/api/toot',
'POST',
-- replace {OTTER_API_TOKEN} with your own token
'{"Content-type":"application/json","Authorization":"{OTTER_API_TOKEN}"}',
'{}',
'1000'
);
TODO:
- document the PostgreSQL trigger function that calls the
/api/toot
endpoint
- Add the new type to the types enum
ALTER TYPE type ADD VALUE '???';
- Run
pnpm run supabase:types
to update the TypeScript types - Add a new
case
to theTypeToIcon
component - Add a new
TypeRadio
component to theBookmarkForm
component
I use various other tools to make Otter even better:
- Raycast extension (not currently on the Raycast extension marketplace)
- Chrome extension (not currently on the Chrome webstore)
- Apple Shortcut - download this shortcut and update your Otter instance URL within it. Then you can add it to your iOS share sheet and quickly add new bookmarks to Otter
- Page scraper Cloudflare worker used to scrape the metadata of a URL. This is used when adding new bookmarks to Otter
- Mastodon to Supabase Cloudflare worker used to backup my Mastodon toots to Supabase
Made by Zander • zander.wtf • GitHub • Mastodon