Skip to content

Widget Templates

Persistent widgets live on the Home Screen, the Lock Screen, StandBy, and the Apple Watch. Unlike Live Activities, they are not tied to an ongoing activity: you create a widget once in the app, picking its template and slug, then update its content whenever you like via the API, and Aivi pushes the change to every device that displays it.

Ten templates cover the common shapes of glanceable data. Pick the one that matches yours; each card jumps to the template’s schema and examples.

The content object you send must match the widget’s template schema. Widget templates reuse the Live Activity building blocks ( colors, icons, values, and formatters), so the vocabulary is the same across both.

Every template renders at every Home Screen size, small through extra large, on the Lock Screen, and on the Apple Watch. The data-rich templates put the larger canvases to work with more data; the simpler ones scale to fit.

Widgets are Aivi’s persistent, best-effort layer. Knowing how updates travel helps you pick the right tool:

  • Content pushes arrive in minutes, not seconds. Updating a widget stores the content and sends a low-priority background push to every device showing it. iOS batches and budgets these pushes to save battery, so a change typically appears within minutes: often faster, occasionally slower (Low Power Mode, a sleeping device). Design for “latest known state”, not for real-time.
  • Predictable data stays live without pushes. Anything the device can compute on its own keeps ticking between pushes: the Progress template’s end_date countdown and self-advancing bar, the Countdown target, the time_since / time_until formatters, and the Prices timeline highlighting the current period. One push can keep a widget correct for hours or days; prefer this over frequent pushes.
  • Real-time belongs to Live Activities. If you need second-by-second updates during an ongoing task, use a Live Activity: that is the layer iOS budgets for real-time. A widget can sit alongside it as the persistent summary.

By default a widget shows its last content indefinitely, with no judgement about age; only you know your update cadence. Set stale_after (in seconds) to opt in to staleness: once the content is older than the threshold, the widget visually demotes it and shows an “as of 14:32” line instead of presenting old data as current. You can set it when creating the widget in the app, or per request via the API.

ID: status

At-a-glance state: an icon, a hero reading, and a state line.

Status widget at the medium size: a 21° hero reading, a Comfortable state line, and a thermometer icon.

Use the Home Assistant blueprint to keep a Status widget in sync with your sensors.

FieldTypeDescriptionRequired?
template"status"Identifies this template.Yes
valueValueThe hero reading. Supports text colors and the self-ticking time_since / time_until formatters. When absent, the state takes its place.No
stateValueThe supporting line under the hero.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
{
"template": "status",
"value": { "value": "21°" },
"state": { "value": "Comfortable", "text_color": "green" },
"icon": { "name": "thermometer.medium", "primary_color": "orange" }
}

ID: progress

A live progress bar or countdown. With an end_date set, a single push keeps the widget counting down and the bar advancing on its own.

Progress widget at the medium size: a washer counting down 29:59 with a Washing state line and a 65% progress ring.

Use the Home Assistant blueprint to keep a Progress widget in sync with your sensors.

FieldTypeDescriptionRequired?
template"progress"Identifies this template.Yes
progressProgressBarProgress bar configuration: a simple single-color bar or a segmented bar.Yes
stateValueThe state line (for example “Washing”).No
end_datestringISO 8601 timestamp. When set in the future, the widget shows a live countdown and, for simple bars, a self-advancing bar, with no extra pushes needed. Segmented bars stay static.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
{
"template": "progress",
"progress": { "style": "simple", "value": 0.65, "color": "cyan" },
"state": { "value": "Washing" },
"end_date": "2026-07-01T15:42:00Z",
"icon": { "name": "washer.fill", "primary_color": "cyan" }
}

ID: gauge

A numeric reading on an instrument dial.

Gauge widget at the medium size: a 21.5°C reading on a cool-to-warm gradient dial spanning 0 to 40.

Use the Home Assistant blueprint to keep a Gauge widget in sync with your sensors.

FieldTypeDescriptionRequired?
template"gauge"Identifies this template.Yes
valuefloatThe reading.Yes
min_valuefloatDial minimum. Default: 0.No
max_valuefloatDial maximum. Default: 1.No
unitstringUnit shown with the reading (for example "°C").No
labelstringLabel shown with the reading (for example "Living room").No
colorColorSolid dial color.No
gradientColor[]2–4 gradient stops for the dial.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
{
"template": "gauge",
"value": 21.5,
"min_value": 0,
"max_value": 40,
"unit": "°C",
"label": "Living room",
"icon": { "name": "thermometer.medium" }
}

ID: battery

Device battery levels in Apple’s Batteries idiom: level rings with device icons, and a device list at the large sizes. Made for home-automation devices (vacuums, locks, cameras, sensors) that Apple’s own widget cannot show.

Battery widget at the medium size: four battery level rings with device icons, one charging and one low in red.

Use the Home Assistant blueprint to keep a Battery widget in sync with your sensors. Requires Home Assistant 2025.7 or newer.

FieldTypeDescriptionRequired?
template"battery"Identifies this template.Yes
devicesDevice[]1–8 devices, shown in the order you send them. Small and medium show up to four rings; large lists up to eight devices.Yes
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
FieldTypeDescriptionRequired?
namestringDevice name, shown in the large list.Yes
levelfloatBattery percentage, 0–100.Yes
chargingboolAdds the charging bolt. Default: false.No
iconstring | IconSymbol shown inside the ring.No
colorColorRing color override. By default rings are green, or red at 20 percent and below.No
{
"template": "battery",
"devices": [
{ "name": "Robot vacuum", "level": 68, "icon": "fan.fill" },
{ "name": "Door lock", "level": 45, "charging": true },
{ "name": "Doorbell cam", "level": 92, "icon": "video.fill" }
]
}

ID: budget

A top-level budget plus up to six category breakdowns, made for finance and budgeting. Renders at the large widget sizes too.

Amounts are structured money, not preformatted strings: send numbers or decimal strings, and the device formats them for the user’s locale and the given currency (symbol placement, grouping, and fraction digits, so JPY gets 0 and USD gets 2). Prefer decimal strings: a JSON number cannot carry a trailing zero.

Budget widget at the medium size: $980.70 remaining of $1,500 with a draining ring, next to Food, Vehicle, and Gadgets category rings.

Use the Home Assistant blueprint to keep a Budget widget in sync with your sensors. Requires Home Assistant 2025.7 or newer.

FieldTypeDescriptionRequired?
template"budget"Identifies this template.Yes
totalEntryThe top-level budget line. The widget name serves as its label.Yes
categoriesEntry[]Up to 6 category lines, shown in the order you send them.No
currencystringISO 4217 code (3 uppercase letters); one currency per widget.Yes
display"remaining" | "spent"Which figure headlines everywhere; the ring follows it, so remaining mode drains toward empty while spent mode fills up. Overspending shows a negative remainder in red. Default: "remaining".No
subtitleValueShown with the total, for example “20 days left”. Supports the time_until formatter for a self-updating line.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget.No
tap_urlstringTap action URL to open when the widget is tapped.No
FieldTypeDescriptionRequired?
spentnumber | stringAmount spent.Yes
budgetnumber | stringBudgeted amount, greater than 0. When present the entry gets a progress ring and the total shows an “of $1,500” line. When absent the entry shows the spent amount with a plain icon.No
labelstringThe category name.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
colorColorThe ring color. Falls back to the icon color, then the accent.No
{
"template": "budget",
"currency": "USD",
"display": "remaining",
"total": {
"spent": "519.30",
"budget": "1500",
"icon": { "name": "banknote", "primary_color": "yellow" },
"color": "yellow"
},
"subtitle": { "value": "20 days left" },
"categories": [
{
"spent": "157.60",
"budget": "300",
"label": "Food",
"icon": "fork.knife",
"color": "blue"
}
]
}

ID: trend

A current reading with a compact history sparkline: temperature, humidity, power draw, or anything you already track as a series. You post the recent history; the device draws and scales the chart. Renders at the large widget sizes too.

Trend widget at the medium size: a 21.4° hero reading with a Rising state line and an orange history sparkline.

Use the Home Assistant blueprint to keep a Trend widget in sync with your sensors.

FieldTypeDescriptionRequired?
template"trend"Identifies this template.Yes
valuefloatThe current reading, shown as the hero.Yes
pointsfloat[]Recent history, 2–48 points, oldest first. The device scales the sparkline to the data.Yes
unitstringUnit shown with the reading (for example "°").No
min_valuefloatFixed lower chart bound. Unset scales to the data.No
max_valuefloatFixed upper chart bound. Unset scales to the data.No
stateValueSupporting line under the hero (for example “Rising”).No
colorColorSparkline color. Falls back to the accent, then the icon color.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
{
"template": "trend",
"value": 21.4,
"unit": "°",
"points": [18.2, 18.9, 19.6, 20.8, 21.6, 21.2, 20.9, 21.4],
"state": { "value": "Rising" },
"icon": { "name": "thermometer.medium", "primary_color": "orange" }
}

ID: countdown

A moment in time rendered as a self-updating countdown: garbage day, the next departure, an appliance finishing. One push sets the target; the device keeps the countdown current with no further pushes.

Countdown widget at the medium size: 2 days, 2 hr until garbage day, with a Paper & cardboard subtitle and the target date.

Use the Home Assistant blueprint to keep a Countdown widget in sync with your sensors.

FieldTypeDescriptionRequired?
template"countdown"Identifies this template.Yes
targetstringISO 8601 timestamp (with timezone) to count down to.Yes
subtitleValueSupporting line (for example “Paper & cardboard”).No
expired_textstringShown once the target has passed. Without it, the widget shows the time elapsed since the target instead.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
{
"template": "countdown",
"target": "2026-07-04T06:30:00Z",
"subtitle": { "value": "Paper & cardboard" },
"expired_text": "Out now",
"icon": { "name": "trash.fill", "primary_color": "green" }
}

ID: list

Rows of labeled values: the generic multi-entity readout for anything that does not fit a more specific template. Small and medium show up to four rows (small drops the labels to fit); large lists up to eight. Renders at the large widget sizes too.

List widget at the medium size: four labeled rows: Living room 21.4°, Front door Locked in green, Humidity 54%, Garage Closed.

Use the Home Assistant blueprint to keep a List widget in sync with your sensors. Requires Home Assistant 2025.7 or newer.

FieldTypeDescriptionRequired?
template"list"Identifies this template.Yes
rowsRow[]1–8 rows, shown in the order you send them.Yes
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
FieldTypeDescriptionRequired?
labelstringThe row label.Yes
valueValueTrailing value, with optional text color and formatters.No
iconstring | IconLeading symbol.No
{
"template": "list",
"rows": [
{
"label": "Living room",
"value": { "value": "21.4°" },
"icon": { "name": "thermometer.medium", "primary_color": "orange" }
},
{
"label": "Front door",
"value": { "value": "Locked", "text_color": "green" },
"icon": "lock.fill"
},
{
"label": "Humidity",
"value": { "value": "54%" },
"icon": { "name": "humidity.fill", "primary_color": "teal" }
}
]
}

ID: prices

A price timeline for dynamic tariffs: hourly electricity prices and the like. Post the periods you know (for example today plus tomorrow, hourly); the device charts them and highlights the current one, so a single nightly push stays correct all day. Renders at the large widget sizes too.

Prices widget at the medium size: a 42.9 ct/kWh hero reading marked High, with a day of hourly price bars colored by level and the current hour highlighted.

Use the Home Assistant blueprint to keep a Prices widget in sync with your sensors.

FieldTypeDescriptionRequired?
template"prices"Identifies this template.Yes
entriesEntry[]1–48 pricing periods in strictly increasing start order. Each period lasts until the next one begins.Yes
unitstringDisplay unit (for example "ct/kWh"); prices are unit-agnostic numbers.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No
FieldTypeDescriptionRequired?
startstringISO 8601 timestamp the period starts at.Yes
pricefloatThe price for the period.Yes
level"low" | "medium" | "high"Explicit price banding. Unset lets the device derive bands from the posted range.No
{
"template": "prices",
"unit": "ct/kWh",
"entries": [
{ "start": "2026-07-02T00:00:00+02:00", "price": 14.2 },
{ "start": "2026-07-02T01:00:00+02:00", "price": 12.8 },
{ "start": "2026-07-02T02:00:00+02:00", "price": 11.9, "level": "low" },
{ "start": "2026-07-02T03:00:00+02:00", "price": 22.4 }
]
}

ID: energy

Home energy at a glance: generation sources, grid, battery, and home consumption. Sources are generation of any kind (solar, wind, hydro, a generator) and default to the solar presentation when unnamed. Renders at the large widget sizes too.

Energy widget at the medium size: Solar 3.2 kW, Grid -1.4 kW, Battery 800 W at 76%, and Home 1 kW, each with its icon.

Use the Home Assistant blueprint to keep a Energy widget in sync with your sensors. Requires Home Assistant 2025.7 or newer.

FieldTypeDescriptionRequired?
template"energy"Identifies this template.Yes
sourcesNode[]Up to 3 generation sources.No
gridNodeThe grid connection.No
batteryNodeThe home battery.No
homeNodeHome consumption.No
iconstring | IconAn SF Symbols icon name or an Icon with rendering options.No
accentColorPalette color that themes the whole widget. Falls back to the icon color.No
tap_urlstringTap action URL to open when the widget is tapped.No

All four slots share this one node shape; the slot a node sits in decides its defaults and how its power sign is read. In practice level belongs to the battery node and name chiefly renames generation sources; the remaining fields apply everywhere.

FieldTypeDescriptionRequired?
namestringDisplay label overriding the slot’s default (“Solar”, “Grid”, …); chiefly for generation sources (“Wind”, “Hydro”).No
powerfloatInstantaneous power in watts. The sign follows the slot’s convention (see above).Yes
todayfloatToday’s cumulative energy in kWh.No
levelfloatCharge percent (0–100); battery node only.No
iconstring | IconSymbol for the node.No
colorColorColor override for the node.No
{
"template": "energy",
// Unnamed sources render as "Solar"; set "name" for "Wind", "Hydro", …
"sources": [{ "power": 3200, "today": 12.4 }],
// Negative grid power: exporting. Positive would be importing.
"grid": { "power": -1400, "today": 3.1 },
// Positive battery power: charging. Negative would be discharging.
"battery": { "power": 800, "level": 76 },
"home": { "power": 1000, "today": 9.8 }
}

The quickest path is the ready-made widget blueprints: one per template, imported in a few clicks, with the payload plumbing handled for you.

For anything the blueprints don’t cover, widgets use the same RESTful command pattern as Live Activities. Add a command for the widget endpoint to configuration.yaml:

rest_command:
update_widget:
url: "https://api.getaivi.app/widget/{{ slug }}"
method: PATCH
headers:
content-type: application/json
authorization: Token [token]
payload: "{{ payload }}"

Then call it from an automation whenever the source data changes. This example keeps a Gauge widget in sync with a temperature sensor:

- triggers:
- trigger: state
entity_id: sensor.living_room_temperature
actions:
- action: rest_command.update_widget
data:
slug: living-room
payload: >-
{
"content": {
"template": "gauge",
"value": {{ states('sensor.living_room_temperature') | float(0) }},
"min_value": 10,
"max_value": 35,
"unit": "°C",
"label": "Living room",
"icon": "thermometer.medium"
}
}

There is no need to update on a timer: widgets show the latest known state, so updating only when the value actually changes is enough. For slow-moving data (battery levels, prices), a time-pattern trigger every hour or a single nightly update works just as well.

Shortcuts can update a widget when run manually, from the Action button, or on a schedule via a personal automation, no server required.

  1. Add a Text action containing the request body:

    {
    "content": {
    "template": "progress",
    "progress": { "style": "simple", "value": 0.6, "color": "cyan" },
    "state": { "value": "1.5 of 2.5 L" },
    "icon": { "name": "drop.fill", "primary_color": "cyan" }
    }
    }

    Build the dynamic parts (numbers, dates) with earlier Shortcuts actions and insert them into the Text as variables.

  2. Add a Get Contents of URL action pointing at https://api.getaivi.app/widget/water-intake and expand Show More:

    • Method: PATCH
    • Headers: AuthorizationToken YOUR_API_TOKEN and Content-Typeapplication/json
    • Request Body: File, set to the Text from step 1
  3. Run the shortcut. The widget updates on every device that shows it.

For the full endpoint reference (request body, stale_after, responses, and errors), see Update a widget in the API reference.