React + FastAPI image labeling tool with multi-category labels, keyboard shortcuts, filtering, and CSV preview/export.
- Click Upload Folder to import a local directory of images (each folder becomes a project).
- New projects start with no categories/labels; create your own schema or reuse one.
- In Manage Categories & Labels, use Explore Schemas to reuse schemas from other projects.
- Create label categories and labels, then label images per category.
- Keyboard shortcuts:
1-9: apply label in active categoryShift+1-9: toggle label in active category←/→: previous/next imageX: clear labels in active category
- Filter button:
- toggle filter active on/off,
- choose
AnyorAll, - optionally use export selection as filter source.
- Unlabeled button:
- select categories to show images missing labels in those categories,
- selecting a category there also activates that category for hotkeys.
- Preview CSV opens a preview tab where you can inspect rows, edit filename, and click Download CSV.
- If nothing opens, allow popups for localhost.
![]() |
![]() |
![]() |
![]() |
- SQLite DB:
data/labeling.db - Uploaded files:
uploads/ - Supported image formats: JPG, JPEG, PNG, GIF, BMP, WebP
- In Docker mode, data lives in named volumes:
labelling_dataandlabelling_uploads.
Run everything from the repo root:
cd /path/to/labelling
./run_labelling.shThis script:
- creates
.venvif needed, - installs backend dependencies,
- starts FastAPI on
http://localhost:8000, - starts the frontend on
http://localhost:5173.
Stop both with Ctrl+C.
Make sure Docker Desktop (or Docker daemon) is running first.
Build the image:
cd /path/to/labelling
docker build -t labellingsoftware:local .Run it with persistent local volumes:
docker run --rm \
-p 127.0.0.1:8001:8000 \
-v labelling_data:/app/data \
-v labelling_uploads:/app/uploads \
labellingsoftware:localOr use Compose:
cd /path/to/labelling
HOST_PORT=8001 docker compose up --buildThen open: http://localhost:8001
Backend:
cd /path/to/labelling
.venv/bin/python -m uvicorn server.app:app --reload --host 127.0.0.1 --port 8000Frontend:
cd /path/to/labelling/web
npm install
npm run devYes, network mode is the right approach for synchronization:
- run one central container on one machine/server,
- let all laptops connect to that one instance,
- keep one shared DB and upload store inside that container's volumes.
- no central user management is required (all users share the same project state on that server).
Start compose in network mode on the host machine:
cd /path/to/labelling
HOST_BIND=0.0.0.0 HOST_PORT=8000 docker compose up --build -dThen teammates open http://<host-machine-ip>:8000.
Important: do not run multiple backend containers against the same SQLite file. For one shared backend process, SQLite is fine.
If you want HTTPS, run compose with the HTTPS override (Caddy reverse proxy):
cd /path/to/labelling
LABELLING_HTTPS_HOST=localhost HTTPS_HOST_BIND=127.0.0.1 HTTPS_PORT=8443 HOST_PORT=18000 \
docker compose -f docker-compose.yml -f docker-compose.https.yml up --build -dOpen: https://localhost:8443
For shared lab usage (multiple laptops), run on the host machine with its LAN IP:
cd /path/to/labelling
LABELLING_HTTPS_HOST=<host-machine-ip> HTTPS_HOST_BIND=0.0.0.0 HTTPS_PORT=8443 HOST_PORT=18000 \
docker compose -f docker-compose.yml -f docker-compose.https.yml up --build -dTeammates then open: https://<host-machine-ip>:8443
Caddy uses a local internal CA in this mode. To remove warnings, trust that CA on each client machine.
Export the CA certificate from the host:
cd /path/to/labelling
docker compose -f docker-compose.yml -f docker-compose.https.yml exec caddy \
sh -lc 'cat /data/caddy/pki/authorities/local/root.crt' > caddy-local-root.crtmacOS trust command (run on each laptop, admin required):
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain caddy-local-root.crtAfter trusting the cert, reload the HTTPS page.
This project is actively maintained.
If you want a new feature, please open a GitHub issue:
When possible, include:
- what problem you want to solve,
- the exact workflow you have in mind,
- screenshots or mockups,
- why current behavior is not enough.
For contribution terms, see:
CONTRIBUTING.md
This project uses dual licensing:
- Default public license: PolyForm Noncommercial 1.0.0 (
LICENSE,LICENSES/PolyForm-Noncommercial-1.0.0.md) - Commercial use: requires a separate paid commercial license (
COMMERCIAL-LICENSE.md)
What this means in practice:
- Students, researchers, and other noncommercial users can clone and use it under the noncommercial terms.
- Companies and other commercial users must reach out for a commercial license.



