blurd

blurd logo

Face and licence-plate redaction for image pipelines. The original is never stored — only its SHA-256, its dimensions, and the redacted output.

Deployment guide Source


What it is

A single service that takes an image, blurs the faces and plates in it, and hands back a redacted copy plus a job record. It is machine-to-machine: your backend talks to it, not your users’ browsers.

producer  ──POST /v1/images──▶  blurd  ──▶  redacted blob + job
consumer  ──GET /v1/blobs/by-code/<your own id>──▶  the redacted image

Submission is asynchronous from the start, because an HTTP request will not hold for a batch. You get a job you can query at any point — by job id, by the source SHA, by a metadata filter, or by your own unique code, which is a primary key rather than a metadata row. That last one is the point: it makes a consumer lookup ~13 µs where a metadata filter is ~7 ms.

What it deliberately does not do

  • It does not store your originals. Not on disk, not in the database, not while queued. Spooling queued uploads would be the obvious durability fix and it is refused for this reason.
  • It does not promise anonymisation. Detection is a model; it misses things. blurd reports confidence and flags low-confidence results for review. Treat it as a large reduction in exposure, not as compliance.
  • It is not a photo editor. One job: redact, store, serve.

Numbers, all measured

   
throughput ~3.4 images/s per physical core (CPU-only; no GPU required)
a single instance ~1.16 M images/day
memory 120 MB + 90 MB per worker, sized automatically from the cgroup
stored per image ~333 kB blob + ~19 kB metadata
consumer lookup by your own code ~13 µs
conformance 154 black-box checks, on every backend

Choices it gives you

  options
metadata SQLite · PostgreSQL · MongoDB
blobs local disk · any S3-compatible store
scale one instance · N replicas behind a load balancer
deploy CLI · Docker · Docker Compose · Kubernetes (Helm)

Every combination passes the same 154 checks. Which to pick, and why, is in the deployment guide.

Multi-tenant by construction

One instance serves several applications without them seeing each other. A scoped key is a tenant, not a filter: tags, metadata and your unique codes are namespaced per tenant, so two apps can use the same filename for different images. An out-of-scope read returns 404, never 403 — a 403 would confirm the resource exists.

blurd keys add app-acme  --scope-tag acme
blurd keys add app-fleet --scope-meta appId=fleet

blurd dashboard — stats, filters, facet chips and redacted thumbnails

Try it

git clone https://github.com/javimosch/blurd && cd blurd
./demo.sh          # blurd + a sidecar standing in for the two external apps

Where to go next

   
running it anywhere Deployment guide
the wire contract, schema, blob layout spec/ in the repo
architecture rules and why each exists AGENTS.md
contributing CONTRIBUTING.md
security properties and reporting SECURITY.md

blurd is AGPL-3.0. The plate detector derives from YOLOv9 (GPL-3.0); the face detector is Apache-2.0. Neither model is redistributed by this repository — both are fetched at runtime. Which models, and why.


This site uses Just the Docs, a documentation theme for Jekyll.