Linkhaven is a local-first infinite canvas for bookmarks, images, live charts, news feeds, themes, and reusable layouts. It turns a blank tab into a spatial board where every link has a place, and the same React app powers both the hosted web build and the browser-extension new-tab experience for Chrome, Edge, and Firefox.
Documentation: schulzoli.github.io/Linkhaven
- Infinite canvas with pan, zoom, snap-to-grid placement, marquee multi-select, copy/cut/paste, undo, and format painter
- Link cards, collapsible nested groups, pictures, live charts, and RSS/Atom news feeds on the same board
- Multiple workspaces with a pinned or auto-hiding workspace rail
- Six built-in themes plus saved or imported custom themes and token-level customization
- Reusable templates with preview thumbnails and bundled local images
- Local statistics for link opens, canvas opens, and storage footprint
- No account, mandatory backend, or remote sync requirement
- Pan with right-click drag and zoom with the mouse wheel
- Snap-to-grid placement with configurable snapping behavior
- Marquee select across cards, groups, and picture nodes
- Copy, cut, paste, duplicate, and undo workspace edits
- Keyboard shortcuts and an in-app help panel for fast editing
- Create link cards from URLs; website icons load on request (Menu → Privacy), otherwise cards show a letter or your own image
- Give a card an optional local link (e.g.
http://192.168.1.10:8123next tohttps://home.example.com): a click opens it when it answers, otherwise the main link - Resize cards from 2x2 up to 12x12 grid cells
- Override favicons with uploaded gallery images
- Organize content inside collapsible groups and nested groups
- Drop images onto the canvas as standalone picture nodes
- Add notes: sketch freehand with mouse, pen or finger in an Excalidraw-like hand-drawn style, and double-click to type handwritten text
- Collapsing a group hides every node inside it, including charts and feeds
- Turn it on under Menu → Privacy to get an Auto tab and a workspace built from what you open most: links, news feeds and charts
- Sources: link opens on your own cards, and in the extension the browser's top sites and history (optional permissions, asked for once, read locally)
- With AI arrangement also on, Claude groups the pages using your own Anthropic API key; only page titles and URLs are sent
- Turn on Device sync under Menu → Privacy to keep workspaces, themes and images in step across devices: through a Linkhaven server with a sync code (no account), or through a WebDAV folder you own (Nextcloud, a NAS, …)
- End-to-end encrypted on the device; the server only stores data it can't read
- Self-host everything (web app, sync, news feeds, charts) in one Docker container: doc/SELF_HOSTING.md
- Besides the browser extension, Linkhaven installs as a web app (PWA) on phones, tablets and computers and works offline: schulzoli.github.io/Linkhaven/app/; see doc/APP.md
- Chart nodes plot a time series from a WebSocket or SSE feed: ranges from 1D to Max, price or % change, moving averages, log scale, CSV export
- Charts inside a group follow the group's settings; any chart can keep its own value
- News feed nodes merge several RSS or Atom feeds into one list with filter, sort, time window, and per-source toggles; each article opens in a new tab
- Optional local servers ship with the repository:
npm run feed:charts(market data) andnpm run feed:news(feed proxy). See doc/CHART_FEED.md and doc/NEWS_FEED.md
- Built-in themes: Excalidraw, Blueprint, Minimal, Nord, Sunset, and Neon
- Save the current appearance as a custom theme, export it, or import
.linkhaven-theme.json - Save selected canvas content as reusable templates with preview thumbnails
- Download template exports as
.template.jsonfiles - Create, rename, reorder, delete, and switch between multiple workspaces
- Export the current canvas as a
.linkhaven.zipbundle - Bundle exports can include the current workspace, gallery images, saved templates, and saved custom themes
- Import can either replace the current canvas or create a new workspace
- Statistics stay local and cover card counts, group counts, link opens, canvas opens, and storage usage
- Windows, macOS, or Linux
- Node.js 22 or later
- npm 10 or later
npm install
npm run devOpen http://localhost:5173.
npm run build| Command | Description |
|---|---|
npm run dev |
Start the Vite development server |
npm run build |
Type-check and build the production app |
npm run preview |
Preview the production build locally |
npm run server |
Start the Linkhaven server |
npm run selfhost |
Build the web app and serve it with sync |
npm run feed:charts |
Start the reference chart feed server |
npm run feed:news |
Start the RSS/Atom feed proxy |
npm run docs:build |
Build the documentation site into site/ |
npm run lint |
Run ESLint with zero warnings allowed |
npm run format |
Format the repository with Prettier |
npm run test |
Run Vitest with coverage |
npm run test:watch |
Run Vitest in watch mode |
npm run test:e2e |
Run Playwright end-to-end tests |
npm run build:extension |
Build the browser extension package |
npm run deploy |
Run the extension deployment script |
npm run deploy:chrome |
Publish only the Chrome build |
npm run deploy:edge |
Publish only the Edge build |
npm run deploy:firefox |
Publish only the Firefox build |
npm run deploy:dry |
Dry-run the extension deployment flow |
Linkhaven can be packaged as a browser-extension new-tab experience for Chrome, Edge, and Firefox.
npm run build:extensionThis creates dist-extension/ with the bundled app, manifest, icons, and privacy page.
Chrome and Edge:
- Open
chrome://extensionsoredge://extensions - Enable Developer mode
- Click Load unpacked
- Select
dist-extension/
Firefox:
- Open
about:debugging#/runtime/this-firefox - Click Load Temporary Add-on
- Select
dist-extension/manifest.json
To release, run Actions → Release with the new version and the stores to publish to; details in extension/EXTENSION.md.
npm run server # device sync, news feed proxy and chart feed on http://127.0.0.1:8790The same server runs locally or as the public sync service (Docker + automatic HTTPS); see doc/SERVER.md.
One container serves the web app together with sync, the news feed proxy and charts; opened from there, the app uses it without any setup:
LINKHAVEN_DOMAIN=links.example.com SELF_HOSTED=on docker compose -f server/docker-compose.yml up -d --buildAt home without a domain, with Tailscale or your own reverse proxy: see doc/SELF_HOSTING.md.
npm run build:pwa # installable, offline-capable web app in dist-pwa/It is published with the docs to schulzoli.github.io/Linkhaven/app/. Installing it on phones and computers and setting up device sync are described in doc/APP.md.
Linkhaven is local-first.
- IndexedDB is the primary persistence layer for workspaces, templates, themes, image metadata, and image blobs
- localStorage is used as a lightweight snapshot and fallback layer for workspace state and workspace-directory metadata
- Local usage insights stay on the current device and power the in-app Statistics view only
- Out of the box Linkhaven is a pure link dashboard that makes no network requests and needs no server: no browser permissions, no charts or feeds, no icon lookups, no AI
- Every feature that uses the network or reads browser data is off by default and has its own switch with live status under Menu → Privacy: website icons, Google favicons, app icons, chart and news feed nodes, Check Links, the Auto dashboard and its AI arrangement, and device sync
- With Website icons on, creating a link card fetches the site's
/favicon.icoonce and caches it locally; with Google favicons on, Google's public favicon service is the fallback (never asked about local addresses) - With App icons on, homelab cards (Jellyfin, Radarr, Home Assistant, …) are matched to an app by name, address or default port on the device, and only that icon is loaded from the dashboard-icons collection on jsDelivr; Data → Find app icons does the same for existing cards
- Chart nodes connect only to the feed server URL set on the node (by default the optional local server on
127.0.0.1) - News feed nodes load the feeds you add through the feed proxy set on the node (by default the optional local proxy on
127.0.0.1), or directly when the proxy is cleared; article images load from the news sites (can be turned off per node) - Check Links in the Data tab sends a
HEADrequest to each link card's URL, only when you start it - Device sync talks only to the sync server or WebDAV folder you choose, and encrypts everything on the device first
- No account, remote sync requirement, or third-party analytics or behavioral tracking is built into the app
For deeper persistence details, see doc/STORAGE.md. The privacy policy is published at schulzoli.github.io/Linkhaven/privacy/ and ships in the app at public/privacy/index.html.
- Documentation website, built from
doc/bynpm run docs:build - doc/APP.md for the web app (PWA) and device sync
- doc/SELF_HOSTING.md to run all of Linkhaven on your own server
- doc/SERVER.md for the Linkhaven server (sync, feed proxy, charts) and how to host it
- doc/STORAGE.md for persistence, bundle, and migration details
- doc/CHART_FEED.md for chart nodes and the feed protocol
- doc/NEWS_FEED.md for news feed nodes and the feed proxy
- doc/CANVAS_ENGINE.md for the canvas engine and optional card effects
- extension/EXTENSION.md for extension packaging and release workflow
- extension/STORE_LISTING.md for store-copy and reviewer notes
- public/privacy/index.html for the standalone privacy page
- CONTRIBUTING.md for contribution workflow
If Linkhaven is useful to you and you want to support more polish, testing, and store-release work, you can do that here:







