Swipe-review your Immich library: right = keep, left = trash. Like a dating app, but for photos (and videos).
Screenshots are sanitized (no real photos or API keys).
- Swipe (touch/mouse) or use keyboard/buttons
- Random or chronological review (oldest/newest first)
- Skip videos toggle
- Favorite toggle (press
F) - Add-to-album (+ configurable
0–9hotkeys) - Undo (Ctrl/⌘+Z or ↑)
- Reviewed cache + stats persisted per server/user
- Preloads the next asset
| Action | Gesture / Key | Button |
|---|---|---|
| Keep | Swipe right / → |
✓ |
| Delete (moves to trash) | Swipe left / ← |
✕ |
| Undo | Ctrl/⌘+Z or ↑ |
↶ |
| Favorite | F |
♡ |
| Add to album | 0–9 (configured) |
Album icon |
npm install
npm run devOpen http://localhost:5173.
cp env.example .env
# edit .env
docker compose up --buildOpen http://localhost:2293.
Note: .env values are passed as build args and end up in the frontend bundle. Changing .env requires a rebuild.
This repo includes a GitHub Actions workflow that builds and deploys the SPA to GitHub Pages on every push to main.
After enabling Pages in your repo settings, your URL will be:
https://<owner>.github.io/<repo>/
See env.example.
VITE_SERVER_URL=https://immich.example.com
VITE_USER_1_NAME=User 1
VITE_USER_1_API_KEY=your-api-keyTip: VITE_SERVER_URL can be the base URL (recommended) or end with /api — the app normalizes it.
Behavior:
- 1 user configured: auto-login
-
1 users configured: user selection screen (
/select-user) - no
.envusers: manual login (/login), stored inlocalStorage
Note: user slots are currently wired up to VITE_USER_5_* in src/vite-env.d.ts, Dockerfile, and docker-compose.yml.
Security note: VITE_* variables are embedded into the compiled frontend. Only use VITE_USER_*_API_KEY for private deployments/images.
If you don’t configure .env users, the app asks for:
- Immich Server URL
- API key
Those values are stored in localStorage under immich-swipe-config.
All requests use Immich’s API (/api/...) with the x-api-key header, so your Immich instance (or reverse proxy in front of it) needs to allow CORS.
If VITE_SERVER_URL points directly to your Immich instance (for example https://immich.example.com), your browser calls https://immich.example.com/api/....
You’ll need CORS headers. For Nginx Proxy Manager, add:
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'X-Api-Key, X-Target-Host, User-Agent, Content-Type, Authorization, Range, Accept' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range, Accept-Ranges' always;
if ($request_method = OPTIONS) { return 204; }See also: https://docs.immich.app/administration/reverse-proxy/
immich-swipe-config(manual login: server URL + API key)immich-swipe-themeimmich-swipe-skip-videosimmich-swipe-stats:<server>:<user>(keep/delete counters)immich-swipe-reviewed:<server>:<user>(already reviewed IDs + decision)immich-swipe-preferences:<server>:<user>(order mode + album hotkeys)
Minimum:
asset.readasset.delete
If you want albums and favorites, grant the corresponding read/update permissions as well.
npm run dev(Vite,5173,--host)npm run buildnpm run previewnpm run type-checknpm test



