Fork of Glass Keep with local-first sync (offline support), real-time multi-device sync, multi-language i18n support, UI improvements, and a native Android app.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
A native Android wrapper is available for GlassKeep, turning your self-hosted instance into a full mobile app.
Download the latest APK from the Releases page.
- Connect to your server — enter your GlassKeep URL on first launch, the app remembers it
- Pull-to-refresh — swipe down on the home screen to reload
- Photo picker support — add images from your gallery (Android 13+ photo picker compatible)
- Theme-aware status bar — status bar and navigation bar colors change to match the note you're editing
- Long-press back button — hold the back button for 3 seconds to switch server
The Android source code is in the
android/directory. Build it with Android Studio.
- Works offline — create, edit, reorder, pin, archive, trash and restore notes without network
- Changes are queued locally (IndexedDB) and synced automatically when the server is reachable
- Real-time sync between devices via SSE (Server-Sent Events)
- Smart conflict handling — queue collapsing merges rapid edits into a single request
- Sync status indicator — shows offline (grey), syncing (blue), or synced (green) in real time
- Green = everything is done: local queue drained AND remote changes fetched and displayed
- Automatic recovery with retry logic after network loss (including mobile-specific stale socket handling)
- Complete i18n architecture with locale auto-detection based on browser settings
- Full UI translation support (notes, editor, modal, admin, toasts, dates, placeholders...)
- Currently implemented: English + French — easy to add more languages
- Missing translation keys gracefully fall back to English
- When creating a note: a dropdown suggests existing tags as soon as you click the tag field
- When editing a note: same suggestion system with dropdown
- Add tags via Enter, comma, click, paste or Backspace to remove
- Multi-tag filter in the sidebar — Ctrl+click for multi-select with OR logic
- Material Design SVG icons replacing old emojis in the composer and modal
- Icons in the tag sidebar (notes, images, archive, tag)
- Compact layout — reduced spacing between notes, more columns on wide screens
- Richer note preview — renders Markdown with line breaks (16 lines instead of 6)
- Wider modal — responsive with adapted breakpoints to avoid truncated text
- Deleting a note no longer removes it permanently — it moves to the Trash
- Dedicated Trash view in the sidebar, alongside Home and Archive
- Restore a note from the trash — it returns to its original state (active or archived)
- Permanent deletion is only possible from the Trash, with a clear confirmation dialog
- Works with single notes and bulk selection
- Full EN/FR translations
📋 Full changelog since fork
- Auto-hide header on scroll down
- Adaptive title size based on text length
- Close note with Android back button (History API)
- 2-column grid layout for pinned and regular notes
- Reduced note card padding and title size
- Fixed text overflow on note cards
- Fixed checklist text overflow on cards
- Highlight clickable phone numbers in checklist items
- Disable phone links and checkboxes in note preview
- Themed scrollbars matching note color (light + dark mode)
- Aurora Pastel color theme
- Floating decorative note cards on login background
- App logo above login title
- Saturated color palette inspired by Google Keep
- Material Design icons in composer and tag sidebar
- Modernized icons with compact layout and richer note preview
- Tag suggestions dropdown in composer and modal
- Masonry layout for both pinned and regular notes grid
- Match Google Keep responsive column breakpoints
- Fixed ResizeObserver infinite loop in masonry grid
- Single-click tag filter replaces selection, Ctrl+click for multi-select
- OR logic for multi-tag filtering
- Multi-tag banner moved below tag list
- Hidden multi-tag banner for single tag selection
- Soft delete: notes go to trash instead of being permanently deleted
- Trash view with restore and permanent delete actions
- Archived state preserved through trash/restore cycle
- Composer hidden in trash view
- Bulk trash, restore and permanent delete support
- IndexedDB queue for all write operations (offline-capable)
- SyncEngine with automatic retry, exponential backoff, and queue collapsing
- SSE for real-time cross-device sync with auto-reconnection
- Health check system with rate-limit detection (403/429 backoff)
- Pull tracking (beginPull/endPull) — green status only after full data refresh
- Position interpolation on restore from trash
- Mobile recovery: Connection: close header + progressive retry on visibility/online events
- Service Worker configured to never cache API calls (NetworkOnly for /api/)
- Close note modal with Escape key
- Clicking a card always opens the modal
- Links in cards open in a new tab without opening the modal
- Saving a note no longer closes the modal
- Scroll resets to top when formatting a long note
- Images displayed full-width like Google Keep
- Reset note order option in settings
- Sidebar visibility persisted server-side
- Removed blue focus ring on note close button
- Fixed × button size, cursor-pointer, and drag handle alignment
- Fixed checkbox and × button alignment in task lists
- Fixed note preview height in grid
- Fixed toggle buttons overflowing in settings panel
- Fixed login title and logo covered by decorative cards
- Fixed sidebar flash on load in private browsing
- Fixed code block wrapping in notes
- Fixed note sorting when positions are equal
- Fixed missing "Confirm" i18n key
- Complete i18n infrastructure with locale auto-detection
- English (base language) + French as first implementation
- Translated all toasts, alerts, modals, UI labels, and placeholders
- Locale-aware date formatting (EN: MM/DD/YYYY, FR: DD/MM/YYYY)
- Architecture ready for adding more languages easily
Run the following as root on a fresh Debian-based system:
curl -fsSL https://raw.githubusercontent.com/Victor-root/glasskeep-enhanced/main/install.sh | sudo bashThe script will:
- Install Node.js 20 automatically if not present
- Clone the repo to
/opt/glass-keep/app - Build the app and generate a
.envconfig file - Register and start a systemd service (
glass-keep) - Prompt you for the port (default:
8080)
Re-running the same command on an existing installation brings up an interactive menu with three options:
- Install — fresh installation
- Update — pulls the latest version, rebuilds, and restarts the service. Your notes and config are preserved, but a backup of
/opt/glass-keep/datais recommended before updating. - Uninstall — removes the app, the service, and all your notes (
/opt/glass-keep/datais deleted). This is irreversible.
The script output language adapts to your system locale (English/French).
First install: the install script will prompt you to create an admin account (login + password). No default credentials are hardcoded.
Heads up: the native install script above is the recommended way to run GlassKeep. It's what I develop and maintain, and it's more flexible for day-to-day updates. Docker is provided for NAS users and similar appliances — it works, but it's a secondary target.
The Docker image is HTTP-only (put a reverse proxy in front of it if you need HTTPS) and the AI features are not bundled in it, to keep it light.
Paste this single block into a terminal on your Docker host. It creates the folder, the compose file, and starts GlassKeep:
mkdir -p ~/glasskeep && cd ~/glasskeep && cat > docker-compose.yml <<'EOF'
services:
glasskeep:
image: ghcr.io/victor-root/glasskeep-enhanced:latest
container_name: glasskeep
restart: unless-stopped
ports:
- "8080:8080"
environment:
ADMIN_EMAIL: "admin"
ADMIN_PASSWORD: "admin"
volumes:
- ./data:/data
EOF
docker compose up -dThen:
- Open
http://<your-host>:8080 - Log in with
admin/admin - Change the admin password right away from the admin settings panel
That's it. Your notes, account and the auto-generated JWT secret all live in ~/glasskeep/data/ on the host — back up that folder to back up everything.
cd ~/glasskeep && docker compose pull && docker compose up -dRe-run it whenever you want the latest version. No data loss — the image itself is stateless, and the ./data folder is preserved. The image is rebuilt automatically on every push to main so pull always fetches the freshest build.
If you want to change the port, allow self-registration, pin your own JWT secret, or use a different admin login, the commented reference docker-compose.yml at the root of this repo lists every supported environment variable.
- Minimum: 1 vCPU, 1 GB RAM, 3–5 GB storage
- Recommended: 2 vCPU, 2 GB RAM, 5–10 GB storage
GlassKeep can load a server-side ONNX Llama model on first use. This significantly increases RAM and storage usage.
- Minimum: 2 vCPU, 4 GB RAM, 8–10 GB storage
- Recommended: 4 vCPU, 6–8 GB RAM, 10–20 GB storage
Actual requirements depend on the number of users, the amount of notes/images stored, and whether AI is actively used.
npm install
JWT_SECRET="$(openssl rand -hex 32)" ADMIN_EMAILS="admin" npm run dev- Copy
src/i18n/locales/en.jsto a new file (e.g.it.js) - Translate the values
- Import the new locale in
src/i18n/index.js - Adapt the language detection logic
- Rebuild the app
Missing keys will fall back to English.
JWT_SECRETis automatically generated by the install script and saved in/etc/glass-keep.env— no manual action required. If you run the server outside of the install script, you must set it yourself (the server will refuse to start without a valid, non-placeholder secret). Generate one with:openssl rand -hex 32- Serve over HTTPS for PWA support
- Treat the recovery secret key like a password
MIT — Based on Glass Keep by nikunjsingh93















