Save bookmarks to ActivityWatch with one click!
aw-bookmark is an HTTP server and Firefox extension that allows you to save web page bookmarks directly to ActivityWatch. Track your bookmarked pages with categories and analyze your browsing patterns.
- 🔖 One-click bookmarking via Firefox extension with emoji category buttons
- 📊 Track in ActivityWatch - All bookmarks stored as events in your ActivityWatch database
- 🏷️ Categorize bookmarks - Organize with custom categories (toptopbot, education, crypto, etc.)
- 🚀 Auto-start service - Run as systemd user service on login
- 🌐 Bookmarklet support - Use on sites without CSP restrictions
- 💾 Local and private - All data stays on your machine
aw-bookmark runs a local HTTP server (default: localhost:5601) that receives bookmark requests and stores them as events in your ActivityWatch instance. Use the Firefox extension for the best experience, or bookmarklets for quick access.
- Python 3.12 or higher
- uv package manager
- ActivityWatch server running on 127.0.0.1:5600
- Clone this repository:
git clone https://github.com/alx/aw-bookmark.git
cd aw-bookmark- Install dependencies:
uv syncDevelopment mode (with debug output):
uv run flask --app src.aw_bookmark.server run --debug --host 127.0.0.1 --port 5601Production mode:
uv run flask --app src.aw_bookmark.server run --host 127.0.0.1 --port 5601Alternative (using entry point):
uv run aw-bookmarkSend a bookmark to the server:
curl -X POST http://localhost:5601/bookmark \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "title": "Example Site"}'Expected response:
{"status": "success", "message": "Bookmark stored"}A bookmarklet is a bookmark stored in your browser that contains JavaScript code. When clicked, it executes the code on the current page, allowing you to save bookmarks to ActivityWatch with a single click.
- The aw-bookmark server must be running on localhost:5601
- ActivityWatch server must be running
Option 1: Simple Bookmark (No Category)
The fastest option - just click to save the current page.
javascript:(function(){fetch('http://localhost:5601/bookmark',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:window.location.href,title:document.title})}).then(r=>r.json()).then(d=>alert(d.message||'Bookmark saved!')).catch(e=>alert('Error: '+e));})();Option 2: Prompt for Category
Prompts you to enter a category each time you bookmark a page.
javascript:(function(){const category=prompt('Category (optional):','');const data={url:window.location.href,title:document.title};if(category&&category.trim())data.category=category.trim();fetch('http://localhost:5601/bookmark',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)}).then(r=>r.json()).then(d=>alert(d.message||'Bookmark saved!')).catch(e=>alert('Error: '+e));})();Option 3: Hardcoded Category
Create multiple bookmarklets for different categories (work, personal, etc.). No prompts, just one click. Edit work to your desired category.
javascript:(function(){const category='work';fetch('http://localhost:5601/bookmark',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url:window.location.href,title:document.title,category:category})}).then(r=>r.json()).then(d=>alert(d.message||'Bookmark saved!')).catch(e=>alert('Error: '+e));})();Firefox:
- Show bookmarks toolbar: Right-click menu bar → Bookmarks Toolbar
- Right-click the bookmarks toolbar → New Bookmark
- Enter a name (e.g., "Save to AW" or "Bookmark: Work")
- Paste one of the JavaScript codes above into the URL/Location field
- Click Save
Chrome/Edge:
- Show bookmarks bar: Ctrl+Shift+B (Cmd+Shift+B on Mac)
- Right-click bookmarks bar → Add page
- Enter a name and paste the JavaScript code into the URL field
- Click Save
Safari:
- Show favorites bar: View → Show Favorites Bar
- Bookmarks → Edit Bookmarks
- Create new bookmark, paste code into address field
- Navigate to any webpage you want to bookmark
- Click your bookmarklet in the toolbar
- (If using Option 2) Enter a category or leave blank
- You'll see a confirmation alert
- Check ActivityWatch to see your bookmark event
- "Failed to fetch" error: Ensure aw-bookmark server is running on localhost:5601
- No confirmation appears: Check browser console (F12) for errors
- Bookmarklet doesn't work: Verify you pasted the entire code including
javascript:prefix - CSP/NetworkError on GitHub, Twitter, etc.: These sites block localhost connections via Content Security Policy. The bookmarklet won't work on sites with strict CSP. Try it on Wikipedia, personal blogs, or other sites without CSP restrictions
A browser extension works on all websites (including those with CSP like GitHub) and provides a one-click interface for saving bookmarks.
The Firefox extension is available on addons.mozilla.org: https://addons.mozilla.org/en-US/firefox/addon/aw-bookmark/
-
Open Firefox and go to
about:debugging#/runtime/this-firefox -
Click "Load Temporary Add-on"
-
Navigate to the
extension/directory in your cloned repository and selectmanifest.json -
The extension icon should appear in your toolbar
- Navigate to any webpage you want to bookmark
- Click the extension icon in the toolbar
- Click one of the emoji buttons for your desired category:
- 🤖 toptopbot
- 📚 education
- ✨ ahbon
- 😂 permalol
- 🏛️ politilol
- 💰 crypto
- 👤 self
- The bookmark is saved and the popup closes automatically
For permanent installation (survives browser restart):
Option 1: Firefox Developer Edition
- Use Firefox Developer Edition or Nightly with extended developer mode enabled
- The extension will persist across restarts
Option 2: Sign and Install
cd extension
zip -r ../aw-bookmark-extension.zip .
cd ..Then sign at https://addons.mozilla.org/developers/ and install the signed .xpi file
To have aw-bookmark start automatically when you log in, you can set it up as a systemd user service.
-
Create the systemd user directory if it doesn't exist:
mkdir -p ~/.config/systemd/user -
Create the service file at
~/.config/systemd/user/aw-bookmark.service:[Unit] Description=ActivityWatch Bookmark Server Documentation=https://github.com/alx/aw-bookmark After=network.target [Service] Type=simple WorkingDirectory=%h/aw-bookmark ExecStart=/usr/bin/env bash -c 'cd %h/aw-bookmark && uv run aw-bookmark' Restart=on-failure RestartSec=10 [Install] WantedBy=default.target
Note:
%hexpands to your home directory. If you cloned the repository to a different location, update both paths accordingly. You may also need to specify the full path touv(find it withwhich uv).
-
Reload systemd to recognize the new service:
systemctl --user daemon-reload
-
Enable the service to start automatically on login:
systemctl --user enable aw-bookmark.service -
Start the service immediately:
systemctl --user start aw-bookmark.service
Check service status:
systemctl --user status aw-bookmark.serviceView logs:
journalctl --user -u aw-bookmark.service -fRestart the service:
systemctl --user restart aw-bookmark.serviceStop the service:
systemctl --user stop aw-bookmark.serviceDisable auto-start on login:
systemctl --user disable aw-bookmark.service- Service fails to start: Check logs with
journalctl --user -u aw-bookmark.service - uv not found: Ensure uv is in your PATH. You may need to specify the full path to uv in the ExecStart line
- ActivityWatch not available: Ensure ActivityWatch is running before aw-bookmark starts. You can add a delay with
ExecStartPre=/bin/sleep 5in the service file
Store a bookmark event in ActivityWatch.
Request:
- Method: POST
- Content-Type: application/json
- Body:
{ "url": "<bookmark_url>", "title": "<bookmark_title>", "category": "<optional_category>" }url(required): The URL to bookmarktitle(required): The page title or descriptioncategory(optional): Category for organizing bookmarks. Max 100 characters. Allowed: letters, numbers, spaces,-,_,/,.
Response:
- Success (201):
{"status": "success", "message": "Bookmark stored"} - Invalid JSON (400):
{"error": "Invalid JSON"} - Missing fields (400):
{"error": "Missing required fields: url and title"} - Invalid category (400):
{"error": "Category must be 100 characters or less"}or{"error": "Category contains invalid characters..."} - Server error (500):
{"error": "Internal server error: ..."}
Examples:
# Basic bookmark
curl -X POST http://localhost:5601/bookmark \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "title": "Example Site"}'
# With category
curl -X POST http://localhost:5601/bookmark \
-H "Content-Type: application/json" \
-d '{"url": "https://docs.python.org", "title": "Python Docs", "category": "work/documentation"}'Default configuration:
- Listen host: 127.0.0.1
- Listen port: 5601
- ActivityWatch server: 127.0.0.1:5600
- Bucket ID:
aw-bookmark_{hostname}
Note: When running as a systemd service, you can customize the host and port by modifying the ExecStart line in the service file to use Flask options:
ExecStart=/usr/bin/env bash -c 'cd %h/aw-bookmark && uv run flask --app src.aw_bookmark.server run --host 127.0.0.1 --port 5601'This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.