A self-hosted, all-in-one web toolkit — image, PDF, and utility tools processed entirely in-browser, plus optional video/audio downloaders through a self-hosted Python worker.
A full self-hosted deployment (all 43 tools, including downloaders) also runs on a personal VPS — not publicly linked here, but the setup below reproduces it exactly.
OmniKit bundles 43 tools across image editing, PDF manipulation, text/data utilities, and media downloading into a single Next.js app with a polished, animated UI. Most tools run entirely in memory or in the browser — nothing is written to disk, nothing is uploaded to a third party — which makes them safe to deploy on serverless platforms like Vercel. A smaller set of heavier tools (video/audio downloaders, AI background removal) route through an optional self-hosted Python worker for users who want the full feature set on their own hardware.
| 🖼️ Image tools | Convert, resize, compress, crop, rotate, flip, grayscale, blur, watermark, strip metadata, adjust color, remove backgrounds, erase watermarks |
| 📄 PDF tools | Merge, split, rotate, delete/reorder pages, images→PDF, page numbers, watermark, extract text, PDF→images, compress, unlock, repair |
| 🧰 Utilities | QR codes, hashing, JSON formatting, URL/Base64 encoding, color conversion, JWT decoding, regex testing, Markdown preview |
| ⬇️ Downloaders (self-host only) | YouTube, Instagram, TikTok, Twitter/X, Reddit, Spotify, and generic MP3 extraction via yt-dlp / spotdl |
- Sync tools (most image/PDF/utility tools) run inside a single API route — the file is read into memory, processed with Sharp/pdf-lib, and streamed straight back. No
data/storage, no database, no persistent state. - Client-side tools (JSON formatter, PDF→images, background remover, text utilities) run fully in your browser via WASM/JS — the file never leaves your machine.
- Async tools (downloaders, GPU background removal) enqueue a job that a Python worker picks up, processes with
yt-dlp/spotdl/rembg, and reports progress back through polling. This path is gated behind an environment flag and requires self-hosting.
This split is what lets the same codebase deploy cleanly to Vercel (fast, free, zero-maintenance) and run as a full personal media toolkit on a home server or VPS.
- Frontend: Next.js 15 (App Router), TypeScript, Tailwind CSS, Framer Motion, TanStack Query
- Image/PDF processing: Sharp, pdf-lib, pdfjs-dist
- Worker: Python, FastAPI,
yt-dlp,spotdl,rembg(ONNX), ffmpeg - Queue: Redis (or a file-based queue for Redis-free self-hosting)
- Monorepo: pnpm workspaces (
apps/web,packages/shared,services/worker)
The fastest way to try OmniKit. Downloaders and GPU background removal are unavailable here since Vercel has no persistent worker, but everything else works out of the box.
- Import this repo into Vercel
- Set Root Directory to
apps/web - Leave
NEXT_PUBLIC_ENABLE_DOWNLOADSunset - Set
MAX_FILE_SIZE_MB=4(serverless body size cap) - Deploy — no database or worker required
Requires Docker and Docker Compose.
git clone https://github.com/Abudora-0/omnikit.git
cd omnikit
cp .env.example .env
docker compose up -d --buildOpen http://localhost:3000. All 43 tools are available, including downloaders.
Low-RAM VPS (≈1GB)? Set
NEXT_PUBLIC_ENABLE_HEAVY_WORKER_TOOLS=0in your.envbefore building — this hides the memory-hungry worker-side background remover while keeping the browser-only version and all downloaders working.
pnpm install
pnpm dev # web app → http://localhost:3000
# in a second terminal, for downloaders/bg-remove:
cd services/worker
python -m venv .venv && .venv\Scripts\activate # Windows
pip install -r requirements.txt
python worker.pyDownloaders work via a file-based queue (USE_FILE_QUEUE=true) so a Redis install isn't strictly required for local use — see .env.example.
Downloaders are self-host only, gated behind NEXT_PUBLIC_ENABLE_DOWNLOADS=1, and processed by the Python worker (services/worker/) using yt-dlp and spotdl.
- Enable the feature flag. In Docker this is already set in
docker-compose.yml; for local dev, set it inapps/web/.env.local. - Pick a downloader tool from the Downloads/Audio category — YouTube, Instagram, TikTok, Twitter/X, Reddit, Spotify, or generic MP3 extraction.
- Paste the URL, choose a format/quality, and start the job. Progress streams live; the finished file downloads through your browser.
- ffmpeg is required for merging video/audio streams and MP3 extraction. The Docker image includes it; for local/VPS installs, make sure
ffmpegis onPATH(services/worker/app/ffmpeg.pyalso auto-discovers common Windows install locations).
Some platforms — most notably YouTube (bot/sign-in checks), Instagram (Reels/Stories), and age-restricted X/Twitter posts — require a logged-in session to download. Supply cookies to the worker:
- Log into the platform(s) you need in your regular browser.
- Export your cookies as a Netscape
cookies.txtfile using a browser extension (e.g. "Get cookies.txt LOCALLY"), using its "export all cookies" option so every domain's session is captured in one file — not just the current tab. - Place the file at
services/worker/cookies.txt(already gitignored — never commit this file). - Set
COOKIES_FILE=/app/cookies.txt(Docker) or the absolute local path (non-Docker) in the worker's.env. - Restart the worker.
Notes:
- YouTube in particular rotates session cookies automatically as a security measure, so exported cookies can stop working after a while — if downloads start failing again with a "sign in to confirm you're not a bot" error, just re-export and redeploy
cookies.txt. - yt-dlp needs a JS runtime (Deno, bundled in the Docker image) to solve YouTube's anti-bot "n challenge" — without it, only thumbnail/storyboard formats are returned.
COOKIES_FROM_BROWSER=<browser>is also supported as an alternative to a cookies file, but only works when the worker runs on the same machine as that browser (not viable on a headless VPS).
This is a normal, recurring maintenance step — not a bug. Do this whenever a downloader that used to work suddenly fails with a sign-in/bot-check error.
1. Re-export a fresh cookies.txt
- Open your browser and make sure you're logged into the platform(s) you need (YouTube, Instagram, X, Reddit, etc.)
- Run your cookie-export extension's "Export All Cookies" option (not "current site only") so every domain lands in one file
- Save it, replacing the old file
2. Deploy the fresh file to the worker
Local Docker Compose:
cp path\to\new\cookies.txt services\worker\cookies.txt
docker compose restart workerRemote VPS (from your local machine):
scp -i "path\to\your-ssh-key" "path\to\new\cookies.txt" user@your-vps-ip:~/omnikit/services/worker/cookies.txtthen on the VPS:
docker compose restart worker3. Verify it worked
docker exec omnikit-worker-1 python -m yt_dlp --cookies /app/cookies.txt --list-formats "https://www.youtube.com/watch?v=<any-video-id>"If it lists real video/audio formats (not just sb0–sb3 storyboard entries), the session is valid — retry the download from the UI.
Downloader tools are provided for personal use only. Downloading content from YouTube, Instagram, TikTok, Twitter/X, Reddit, or Spotify may violate those platforms' Terms of Service and/or applicable copyright law. You are solely responsible for how you use these features. Image and PDF tools process files locally/in-memory and carry no such third-party concerns.
User → Next.js (apps/web)
├── Sync tools → API route → registry handler → Sharp / pdf-lib (in memory, streamed back)
├── Client tools → run fully in the browser (JSON formatter, PDF→images, bg-remove, text utils)
└── Async tools → API route → Redis / file queue → Python worker (self-host only)
↑
services/worker/worker.py
apps/web— Next.js frontend, sync-tool API routes, job orchestrationpackages/shared— shared tool definitions, Zod schemas, gating logic (zero dependency on Next.js)services/worker— Python FastAPI-adjacent polling worker for async jobs (yt-dlp,spotdl,rembg)
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_ENABLE_DOWNLOADS |
unset | Set to 1 to reveal downloader/worker tools (requires the worker) |
NEXT_PUBLIC_ENABLE_HEAVY_WORKER_TOOLS |
1 |
Set to 0 to hide the memory-hungry GPU background remover (e.g. on a 1GB VPS) |
MAX_FILE_SIZE_MB |
100 |
Upload size limit (4 on Vercel due to the serverless body cap) |
USE_FILE_QUEUE |
false |
Use a local file-based queue instead of Redis |
REDIS_URL |
redis://127.0.0.1:6379/0 |
Redis connection (ignored when USE_FILE_QUEUE=true) |
STORAGE_DIR / STORAGE_PATH |
./data/storage |
Where async job uploads/results are stored (self-host only) |
MAX_CONCURRENT_JOBS |
2 |
Worker concurrency |
JOB_TTL_HOURS |
24 |
How long job files are retained before cleanup |
COOKIES_FILE |
unset | Path to a Netscape cookies.txt for authenticated downloads |
COOKIES_FROM_BROWSER |
unset | Browser name to read cookies from directly (same-machine only) |
See .env.example for the full annotated list.
omnikit/
├── apps/web/ Next.js frontend + sync-tool API routes
├── packages/shared/ Tool registry, types, gating logic
├── services/worker/ Python async worker (downloaders, bg-remove)
├── docker-compose.yml
└── .env.example
- Jobs stay pending — make sure Redis is running (or
USE_FILE_QUEUE=true) and the worker process is up. - YouTube download fails with a sign-in error — your cookies have likely rotated; re-export and redeploy
cookies.txt. - Video download fails with "requested format not available" — make sure Deno (or another supported JS runtime) is installed for
yt-dlp's challenge solver. - Spotify download fails —
spotdlis fragile against Spotify's API changes; verify ffmpeg is installed and try a direct track URL. - Background removal is slow — the first run downloads the ONNX model; later runs are faster.
MIT