Skip to content

openfoodfacts-proxy

Build Documentation

Docs with MkDocs uv linting: ruff ty prek security: bandit Semantic Versions Copier License

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 toolingserve, import-full, and import-delta commands

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

This project was generated with 🚀 python project template.