openfoodfacts-proxy
A FastAPI proxy for OpenFoodFacts
Supports:
- https://openfoodfacts.github.io/openfoodfacts-server/api/ref-v2/
- https://openfoodfacts.github.io/openfoodfacts-server/api/ref-v3/
- https://search.openfoodfacts.org/docs
Features
- Local-first product reads — serves product data from a local MongoDB cache with automatic upstream fallback
- API v2 and v3 support — compatible with both OFF API versions, including field projection
- Transparent upstream proxying — unrecognized requests are forwarded to the real OFF server
- Full and delta sync — import the complete OFF MongoDB dump or apply incremental delta updates
- Rate limiting — configurable per-endpoint rate limits (product reads, search)
- Search integration — local v2 search with upstream fallback; search-a-licious proxy support
- Taxonomy caching — periodic sync of categories, brands, countries, ingredients, and labels
- Image URL rewriting — rewrite OFF S3 image URLs through your own route/CDN
- Reference data endpoints — CGI-compatible and v2/v3 taxonomy/reference routes
- Facet browsing — serve facet-based product listings from the local cache
- CLI tooling —
serve,import-full, andimport-deltacommands
Installation
With pip:
python -m pip install openfoodfacts-proxy
With uv:
uv add openfoodfacts-proxy
How to use it
CLI
Start the proxy server:
openfoodfacts-proxy serve --host 0.0.0.0 --port 8000
Import the full OFF MongoDB dump:
openfoodfacts-proxy import-full
Apply delta updates:
openfoodfacts-proxy import-delta
Python
from openfoodfacts_proxy.app import create_app
app = create_app()
Supported endpoints
| Endpoint | Description |
|---|---|
GET /api/v2/product/{barcode} |
Product read (v2 format) with optional fields query |
GET /api/v3/product/{barcode} |
Product read (v3 format) with optional fields query |
GET /api/v2/search |
Search products with filters and pagination |
GET /{facet_type}/{facet_value}.json |
Facet-based product listings |
Configuration
All settings are configurable via environment variables with the OFF_PROXY_ prefix:
| Variable | Default | Description |
|---|---|---|
OFF_PROXY_MONGODB_URI |
mongodb://mongodb:27017 |
MongoDB connection string |
OFF_PROXY_MONGODB_DB |
openfoodfacts |
Database name |
OFF_PROXY_OFF_BASE_URL |
https://world.openfoodfacts.org |
Upstream OFF server |
OFF_PROXY_PRODUCT_RATE_LIMIT |
15 |
Max product requests per window |
OFF_PROXY_SEARCH_RATE_LIMIT |
10 |
Max search requests per window |
OFF_PROXY_RATE_LIMIT_WINDOW_SECONDS |
60 |
Rate limit window duration |
OFF_PROXY_UPSTREAM_TIMEOUT_SECONDS |
30.0 |
Timeout for upstream requests |
OFF_PROXY_STARTUP_SYNC_ENABLED |
true |
Run full sync on startup |
OFF_PROXY_SCHEDULER_ENABLED |
true |
Enable periodic delta/taxonomy sync |
OFF_PROXY_REWRITE_IMAGE_URLS |
true |
Rewrite OFF image URLs |
Docker
Dockerfile.aio builds the default all-in-one image and starts MongoDB inside the same container.
Dockerfile builds the app-only image and expects MongoDB to run in a separate container.
Build the all-in-one image:
docker build -f Dockerfile.aio -t openfoodfacts-proxy:aio .
Build the separate-DB image:
docker build -f Dockerfile -t openfoodfacts-proxy:app .
Run the default all-in-one container:
docker compose up --build
Run with a separate MongoDB container:
docker compose -f docker-compose.production.yml up --build
Image URL rewriting is configurable so OFF image URLs can be exposed through your own Cloudflare route instead of leaking S3 bucket details.
Set OFF_PROXY_REWRITE_IMAGE_URLS=false to disable rewriting completely.
The runtime settings are split into OFF_PROXY_IMAGE_ROUTE_BASE_URL, OFF_PROXY_IMAGE_BUCKET_NAME, OFF_PROXY_IMAGE_BUCKET_REGION, and OFF_PROXY_IMAGE_BUCKET_PREFIX.
With the defaults, a source URL like https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.820.400.jpg is rewritten to /images/data/301/762/042/2003/front_en.820.400.jpg.
If you want custom rewriting logic, pass your own OpenFoodFactsUrlMapper implementation into create_app(...).
OFF SDK E2E
The OFF SDK integration suite does not use a dedicated Compose file. It starts the proxy stack directly and always seeds MongoDB from the committed fixture dump plus fixture delta under tests/integration/off_sdk/fixtures/, not from the public OFF dataset.
Run it explicitly so normal test runs stay fast:
OFF_PROXY_RUN_SDK_E2E=1 uv run pytest tests/integration/test_off_sdk_proxy_e2e.py -m off_sdk_e2e
By default the test prefers a real local MongoDB process when mongod and mongosh are available, then falls back to Docker. You can force either mode explicitly:
OFF_PROXY_RUN_SDK_E2E=1 OFF_PROXY_SDK_E2E_MODE=local uv run pytest tests/integration/test_off_sdk_proxy_e2e.py -m off_sdk_e2e
OFF_PROXY_RUN_SDK_E2E=1 OFF_PROXY_SDK_E2E_MODE=docker uv run pytest tests/integration/test_off_sdk_proxy_e2e.py -m off_sdk_e2e
Local mode requires mongod and mongosh on PATH.
The committed fixtures live under tests/integration/off_sdk/fixtures/. The data/off-sdk-e2e/ directory is disposable gitignored runtime state written by the test harness.
Docs
uv run mkdocs build -f ./mkdocs.yml -d ./_build/
Update template
copier update --trust -A --vcs-ref=HEAD
Credits
Metadata
Release files for openfoodfacts-proxy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| openfoodfacts_proxy-0.1.0.tar.gz | 46.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openfoodfacts_proxy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 132.9 kB
Release files / openfoodfacts_proxy-0.1.0.tar.gz
| Download URL | openfoodfacts_proxy-0.1.0.tar.gz |
|---|---|
| Size | 46.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
391257022a2c8c88a35f40018cfa50008de71bccd8c5143b4df40ddcacf4c489
|
|
BLAKE2b-256 checksum How to use checksums |
5f90ab5f1bb3ca25210ee39008a0aefbf8f1ba0db556246baa8af882689f64ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / openfoodfacts_proxy-0.1.0-py3-none-any.whl
| Download URL | openfoodfacts_proxy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 86.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c83b49c7218de20d9ac1da594b94e0bd1d7ce3ef3493db3367ae7e87ebc970ab
|
|
BLAKE2b-256 checksum How to use checksums |
47175b94f89007a9fb418f62f322e1fe2f3609a538483e96caee20368b8e00c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for openfoodfacts-proxy 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.