Track AI service usage inside Home Assistant.
See the [Home Assistant compatibility matrix](docs/compatibility.md) for the tested integration and Home Assistant version combinations.
AI Usage is a custom Home Assistant integration that receives AI tool usage data and turns it into sensors.
It is designed for simple dashboard questions:
- Can my account still use the service?
- How much of the current limit has been used?
- When does the limit reset?
- Did a collector stop sending data?
- How many AI accounts does Home Assistant know about?
The integration currently supports data from [Codex, Ollama Cloud]:
AI Usage does not access your AI account directly and does not log in to external services. It works as an entry point inside Home Assistant.
An external collector sends data to a Home Assistant webhook. The integration validates that data, identifies the account, and updates sensors that you can use in dashboards, automations, and alerts.
This makes it possible to use different sources in the future, such as browser extensions, local scripts, or other small collectors. If you want a ready-made option, you can use the browser extension at https://github.com/alves-dev/ai-usage-extension or implement your own collector.
The integration creates one main device for the webhook and separate devices for each identified AI account.
| Entity | Type | What it shows |
|---|---|---|
sensor.last_ingest_status |
Sensor | Result of the last webhook request handled by Home Assistant, such as ok, invalid_json, or invalid_contract. |
binary_sensor.webhook_problem |
Binary sensor | Turns on when the last webhook request failed validation or ingestion. |
sensor.last_webhook_received_at |
Sensor | When Home Assistant received the latest webhook request. |
sensor.last_source |
Sensor | Collector source of the latest valid payload, such as browser_extension or python_collector. Disabled by default. |
sensor.known_accounts |
Sensor | Number of AI accounts currently known by the integration. |
sensor.last_unscoped_error |
Sensor | Last provider error that could not be tied to a specific account. Disabled by default. |
| Entity | Type | What it shows |
|---|---|---|
sensor.account |
Sensor | Account label and account metadata, using the best available identifier from the payload. |
sensor.plan |
Sensor | Account plan from account_data.plan.type, such as free, plus, or pro. This is a normal account sensor, not a diagnostic-only sensor, because it can be useful in dashboards and automations. |
sensor.status |
Sensor | Provider status for the latest account sample, such as ok, not_authenticated, rate_limited, or provider_unavailable. |
binary_sensor.problem |
Binary sensor | Turns on when sensor.status is not ok. |
sensor.last_sample_age |
Sensor | Age of the last sample received for that account, in minutes. Helps detect stale data even when the last status was ok. |
sensor.last_error |
Sensor | Last provider error code for the account, or none when the latest sample has no error. Disabled by default. |
sensor.collected_at |
Sensor | When the external collector read the usage data from the provider. Disabled by default. |
sensor.last_received_at |
Sensor | When Home Assistant received that account sample. Disabled by default. Enable it to compare with collected_at for collector delay, queueing, or stale data. |
sensor.source |
Sensor | Source that produced the account payload. Disabled by default. |
sensor.request_count |
Sensor | Number of accepted samples received for that account. Disabled by default. |
For each item in usage_data.windows, the integration creates:
| Entity pattern | Type | What it shows |
|---|---|---|
sensor.window_<id>_used_percent |
Sensor | Percent used in the window. |
sensor.window_<id>_available_percent |
Sensor | Percent available, derived by the integration. |
binary_sensor.window_<id>_limit_reached |
Binary sensor | Whether that window reached its limit. |
sensor.window_<id>_reset_at |
Sensor | Timestamp of the next reset. |
binary_sensor.available |
Binary sensor | Whether at least one account window remains available. |
| Entity | Scope | Use it for | Meaning |
|---|---|---|---|
sensor.last_ingest_status |
Webhook | Collector and webhook health | Whether Home Assistant accepted the last webhook request. This can fail even when the provider account itself is fine. |
sensor.status |
Account | Provider sample health | Whether the latest account sample was collected successfully from the provider. ok means the payload is valid and provider data is usable. |
binary_sensor.problem |
Account | Account-level alerts | Turns on when sensor.status is not ok. Use this for provider/account errors such as authentication or rate-limit failures. |
binary_sensor.available |
Account | Usage availability | Whether at least one usage window remains available. |
binary_sensor.window_*_limit_reached |
Account window | Limit alerts | Whether that specific usage window has reached its limit. |
sensor.*_used_percent |
Account window | Usage dashboards | How much of a usage window has already been consumed. |
sensor.*_available_percent |
Account window | Remaining capacity dashboards | How much of a usage window is still available. |
Some diagnostic entities are disabled by default to keep new installations focused on operational sensors. Enable them manually in Home Assistant when you need collector/source debugging, raw receive timestamps, or request counters.
The repository includes a provider-agnostic card for the normalized window entities. It shows remaining capacity, usage, reset countdowns, limit states, and the overall account availability. The progress bar represents consumed capacity, while the percentage displayed on the right represents capacity remaining.
After the integration has received at least one account payload, add AI Usage Windows from the dashboard card picker. The integration serves and registers the card automatically; no JavaScript copy or manual Lovelace resource is required. Restart Home Assistant after installing or updating the integration so the frontend loads the bundled module. Select the account sensor, availability sensor, and the entities for each window. The visual editor lets you select entities directly from Home Assistant, without editing YAML.
Example:
type: custom:ai-usage-windows-card
title: Codex
account_entity: sensor.account
availability_entity: binary_sensor.available
windows:
- label: 5-hour window
used_entity: sensor.window_short_used_percent
available_entity: sensor.window_short_available_percent
limit_entity: binary_sensor.window_short_limit_reached
reset_entity: sensor.window_short_reset_at
- label: Weekly window
used_entity: sensor.window_long_used_percent
available_entity: sensor.window_long_available_percent
limit_entity: binary_sensor.window_long_limit_reached
reset_entity: sensor.window_long_reset_atThe card supports any number of windows and adapts to mobile layouts. Each
window displays its label, remaining percentage, consumed percentage, reset
status, and reset time. The entity ID is the stable technical identity; the
configured label is only the visible name. Use
warning_threshold and critical_threshold to customize the visual warning
levels; their defaults are 40 and 15 percent remaining.
If you have already added this repository to HACS, use:
To add it as a custom repository:
Manual HACS setup:
- Open HACS.
- Go to Integrations.
- Open the three-dot menu.
- Choose Custom repositories.
- Add
https://github.com/alves-dev/ai-usage. - Select Integration as the category.
- Install AI Usage.
- Restart Home Assistant.
After installing and restarting:
- Open Settings > Devices & services.
- Click Add Integration.
- Search for AI Usage.
- Choose a Webhook endpoint ID.
The ID becomes part of the webhook URL. If the ID is:
ia-tool-usage
the URL will be:
http://YOUR_HOME_ASSISTANT:8123/api/webhook/ia-tool-usage
Treat this ID as a secret. Use a long value that is hard to guess.
The integration only creates account sensors after it receives the first valid payload. If you just installed it and do not see Codex or Ollama Cloud sensors yet, that usually means no collector has sent data yet.
When the first valid sample arrives:
- the account appears as a new device;
- sensors are created automatically;
- the account is saved so it comes back after restarting Home Assistant.
AI Usage is designed to avoid sensitive identifiers in internal sensor IDs.
- Real email addresses are not used directly in
unique_id. - Raw webhook payloads are not stored.
- The webhook ID should be treated as a secret.
- Examples and tests should use synthetic data.
Technical details live outside the README so the HACS screen stays easier to read:
- Payload contract
- Device and sensor contract
- AI Usage browser extension
- Home Assistant compatibility
- Changelog
Generate a valid payload without sending it:
python3 scripts/manual_collector.pySend it to a webhook:
python3 scripts/manual_collector.py \
--url "http://homeassistant.local:8123/api/webhook/<WEBHOOK_ID>" \
--provider codex \
--short-used 80 \
--long-used 45The webhook ID is a secret. The script sends only the normalized payload.
The integration and its maintained collectors use the Home Assistant-style
format YYYY.M.patch, for example 2026.8.1. Development builds use the
-dev suffix, for example 2026.8.1-dev. The stable release workflow reads
the release version automatically from custom_components/ai_usage/manifest.json.
After a version change is merged into main, it creates the tag and GitHub
Release automatically. The develop workflow creates a prerelease using the
same manifest version with -dev appended, for example v2026.8.1-dev.
To prepare a new version locally, update all version sources with:
python3 scripts/set_version.py 2026.8.1Main commands for contributors:
uv sync
uv run pytest
uv run ruff check .
uv run ruff format .
scripts/validate-homeassistant-version.shChanges to payloads, sensors, or provider behavior should update the matching
technical documentation in docs/.



