A FastAPI service that collects opt-in OVOS device metrics (wake-word audio, STT utterances, intent matches) into a database for open dataset building. See docs/index.md for the full documentation.
Only if you explicitly opt into wake-word (ww_urls) or STT (stt_urls)
uploads in your device's mycroft.conf. By default, nothing is uploaded at
all. If you only enable intent_urls, the server receives text (the
utterance and matched intent) and never any audio. See
docs/connecting-devices.md for exactly what
each upload contains, and privacy.md for the full policy.
Yes — that's a first-class use case, not an afterthought. See
docs/self-hosting.md for a production Docker Compose
setup, or docs/getting-started.md to try it
locally first. Point your device's open_data config at your own instance
instead of (or in addition to) the public one, and your data never leaves
your network.
cp .env.example .env
docker compose up --build -dAPI on port 8007, dashboard at http://localhost:8007/. Full walkthrough:
docs/getting-started.md.
If unset, the server falls back to a local SQLite file
(sqlite:///./ovos_opendata.db) so it's importable and runnable with zero
configuration for local development and tests. Production deployments
should always set DATABASE_URL to a PostgreSQL DSN — SQLite doesn't
handle concurrent writers well and isn't a good fit once devices are actively
uploading. See docs/self-hosting.md.
The User-Agent: ovos-metrics check returns 404 (not 403) intentionally,
to avoid making the write API discoverable to casual scanners or browsers
poking at the URL.
No personally identifiable information is collected by design — see privacy.md. Because uploads aren't tied to any account or verifiable identity, the server has no way to confirm who submitted a given record, so individual submitted records generally can't be deleted on request. If you need guaranteed control over your data, run your own server (see above) — you control deletion there directly, since it's your database.
All three record types lowercase and strip the language/lang value on
write (app/models.py), so "En-US" and "en-us " both end up stored and
queryable as "en-us".
Controlled by MAX_AUDIO_SIZE_MB (default 10). Exceeding it returns 413.
Yes. Wake-word and STT audio must be a real WAV file (checked by its
RIFF/WAVE header) or the upload is rejected with 400. If the server has
API_KEY configured, uploads also need a matching X-API-Key header or they
get 401. All intake endpoints are rate limited per IP (RATE_LIMIT,
default 60/minute; exceeding it returns 429).
No. Audio is excluded from /intents, /wake_words, and /utterances. Use
/wake_words/{id}/audio or /utterances/{id}/audio to stream individual
files.
GET /intents/export?format=csv (or ?format=json), and the same for
/wake_words/export and /utterances/export, with a hard cap of 100k rows
per request. See docs/datasets.md for column meanings and
notes on building training sets, and
docs/api-reference.md for every filter parameter.
In-memory, server-side, for DASHBOARD_CACHE_TTL seconds (default 60) — see
docs/dashboard.md.
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run pytest test/ -v --cov=app --cov-report=term-missingSee docs/development.md for the full contributor guide.