API

JS reference

Every exported function and type of tauri-plugin-widgets-api, generated from guest-js/.

Every function and type tauri-plugin-widgets-api exports, generated from the JSDoc in guest-js/api/. For how they fit together see the JavaScript API guide. Widget IR types (WidgetConfig, WidgetElement, …) are generated from Rust into guest-js/generated/widget-types.ts; they are documented per element on the Elements pages and in the JSON Schema.

FunctionDescription
setItems()Store a key-value pair in the widget data store.
getItems()Read a previously stored value from the widget data store.
reloadAllTimelines()Reload all registered widget timelines.
reloadTimelines()Reload timelines for a specific widget kind or class.
setRegisterWidget()Register widget provider class names or kind strings.
requestWidget()Request the OS to pin (add) a widget to the home screen.
createWidgetWindow()Create a frameless, transparent desktop widget window.
closeWidgetWindow()Close a previously created desktop widget window.
setWidgetConfig()Send a declarative UI configuration to native widgets.
setWidgetConfigFromPath()Read a WidgetConfig JSON file from disk and push it like setWidgetConfig.
getWidgetConfig()Read the current widget UI configuration from the data store.
reportReceipt()Report that a renderer painted a config (desktop widget.html / tests). Native widgets write receipts themselves; this is for the host webview path.
getWidgetDiagnostics()Live widget instances that recently rendered for group.
getWidgetTrace()Host delivery journal + receipt history for group. Active in debug builds or when WIDGET_DEBUG=1.
flushWidgetTrace()Force-flush the in-memory journal to disk (desktop).
widgetAction()Trigger a widget-action event via the Rust plugin.
onWidgetAction()Listen for widget-action events emitted by widget buttons.
pollPendingWidgetActions()Poll pending widget actions queued by native side (Android fallback path).
startWidgetUpdater()Start a periodic widget updater that calls builder on a fixed interval, sends the returned config to the native widget, and optionally reloads widget timelines.
getActiveWidgets()List placed widgets. Exact on Android (AppWidgetManager) and iOS (WidgetCenter); on desktop: open widget windows plus placements that rendered in the last 48 h (macOS WidgetKit, Windows Widgets Board).
setWidgetData()Values for {{data.path}} placeholders, without resending the layout. Pass null to clear. Layers: config.data < this < the widget's own source fetch.
setWidgetState()Change a widget's local state ({{state.…}}, config state defaults) the way a set tap does: "$toggle", "$inc", "$dec", null removes a key (the default shows again), other values are stored. patch: null clears the stored state. Resolves with the merged state; the app also gets widget-state-changed {widgetId, instance, state}.
getWidgetState()A widget's merged local state: config state defaults, then what taps and setWidgetState stored (the placement's own over the widget's).
setWidgetInstances()Choices the user picks from per placement. iOS / macOS: the Edit Widget sheet of a widget built with TauriInstanceWidget / TauriInstanceProvider. The chosen id is the placement's instance.
registerActivityTemplate()Store a live activity layout on the device (shared store / App Group) under name. layout takes the ActivityContent layout fields (layout, lockScreen, compactLeading, islandCenter, title, …) with {{data.…}}, when, repeat; activities started with template: name then send only data. null removes it.
startActivity()Start a live activity, or update it when id already runs.
updateActivity()Replace the content of a running activity.
endActivity()End an activity; dismissAfterMs keeps the last state visible that long (iOS, desktop).
onActivityState()Activity state changes from the native side (activity-state; no-op where none).
onActivityContent()Activity content changes from the native side (activity-content, e.g. push updates).
getWidgetPushToken()WidgetKit push token (hex) for server-driven widget reloads; null where none exists.
getActivityPushToStartToken()iOS 17.2+ push-to-start token (hex): your server can start a Live Activity with it (APNs event: "start", attributes-type: "TauriActivityAttributes", attributes: {id, group}, content-state: {json: "<ActivityContent JSON>"}). null on other platforms or before iOS issued one; changes arrive via onActivityTokens.
canPromoteActivities()Android 16+: whether activity notifications may show as Live Updates (status-bar chip, lock screen). true where no such gate exists (iOS, desktop, older Android).
openActivityPromotionSettings()Android: open the system screen that allows Live Updates for this app; false if none.
onActivityTokens()Subscribe to Live Activity token changes (iOS only; a no-op elsewhere).
listActivities()Ids of running activities this app started.

Functions

setItems()

async function setItems(key: string, value: string, group?: string): Promise<boolean>

Store a key-value pair in the widget data store.

The storage backend depends on the platform:

  • Android — SharedPreferences scoped by group.
  • iOS / macOS — JSON file in App Group shared container.
  • Desktop — JSON file in the app data directory (macOS: shared container when available).
  • key: Setting name (e.g. "temperature").
  • value: Setting value. Use JSON.stringify() for complex data.
  • group: Widget group identifier: Android: SharedPreferences name; iOS/macOS: App Group ID (e.g. "group.com.example.myapp"); Desktop: arbitrary string used as filename.

Source: guest-js/api/data.ts

getItems()

async function getItems(key: string, group?: string): Promise<string | null>

Read a previously stored value from the widget data store.

  • key: The key to look up.
  • group: The widget group identifier.

Returns: The stored string value, or null if the key was never set.

Source: guest-js/api/data.ts

reloadAllTimelines()

async function reloadAllTimelines(): Promise<boolean>

Reload all registered widget timelines.

  • Android — sends ACTION_APPWIDGET_UPDATE broadcast for every registered provider.
  • iOS / macOS — calls WidgetCenter.shared.reloadAllTimelines().
  • Desktop — emits a "widget-reload" Tauri event that widget windows can listen for.

Source: guest-js/api/reload.ts

reloadTimelines()

async function reloadTimelines(ofKind: string): Promise<boolean>

Reload timelines for a specific widget kind or class.

  • ofKind: Widget class name (Android: fully-qualified class, e.g. "com.example.app.MyWidget"; iOS: widget kind string from your WidgetConfiguration).

Source: guest-js/api/reload.ts

setRegisterWidget()

async function setRegisterWidget(widgets: string[]): Promise<boolean>

Register widget provider class names or kind strings.

Must be called before reloadAllTimelines() or requestWidget().

  • widgets: Array of provider identifiers: - Android: fully-qualified class names (e.g. "com.example.app.MyWidget") - iOS / macOS: widget kind strings from your WidgetConfiguration

Source: guest-js/api/register.ts

requestWidget()

async function requestWidget(): Promise<boolean>

Request the OS to pin (add) a widget to the home screen.

  • Android (API 26+) — calls AppWidgetManager.requestPinAppWidget.
  • iOS / macOS / Desktop — no-op (users add widgets manually).

Source: guest-js/api/register.ts

createWidgetWindow()

async function createWidgetWindow(config: WidgetWindowConfig): Promise<boolean>

Create a frameless, transparent desktop widget window.

When no url is specified the plugin serves its built-in renderer automatically — it reads the config via getWidgetConfig(group) and renders it using vanilla HTML/CSS/SVG. The window has a drag handle at the top and a close button that appears on hover.

You may provide your own url (e.g. "/my-widget.html") if you need full control over the rendering.

Desktop only. Returns an error on mobile.

Example

// Built-in renderer (recommended):
await createWidgetWindow({
  label: "weather",
  width: 280,
  height: 200,
  group: "group.com.example.myapp",
  widgetId: "weather",
  size: "small",
});

// Custom renderer:
await createWidgetWindow({
  label: "weather",
  url: "/my-widget.html",
  width: 280,
  height: 200,
});

Source: guest-js/api/window.ts

closeWidgetWindow()

async function closeWidgetWindow(label: string): Promise<boolean>

Close a previously created desktop widget window.

  • label: The window label used when creating it. Desktop only.

Source: guest-js/api/window.ts

setWidgetConfig()

async function setWidgetConfig(config: WidgetConfig, /** Widget group. Omit to use `plugins.widgets.appGroup` (default `group.<identifier>`). */ group?: string, /** Widget id within the group; must match the native widget's `widgetId`. */ widgetId = "default", /** Skip native widget reload (WidgetKit / AppWidgetManager). * Desktop widget windows are always updated instantly via eval push. */ skipReload = false, /** One placement only (see `getActiveWidgets`): Android `appWidgetId`, the Apple Edit * Widget choice, a window `instance`. Other placements keep the widget-wide config. */ instance?: string): Promise<ApplyOutcome>

Send a declarative UI configuration to native widgets.

The JSON config is stored in the widget data store and read by the native widget extension, which renders it using platform-native components:

  • iOS / macOS — SwiftUI views (VStack, Text, Gauge, etc.)
  • Android — RemoteViews (LinearLayout, TextView, etc.)
  • Desktop — HTML/CSS in the widget window

Returns ApplyOutcome: check written and reload.outcome — a successful invoke no longer means a native reload was performed.

  • config: The widget UI configuration.
  • group: Widget group identifier (same as setItems group).

Example

const outcome = await setWidgetConfig({
  small: {
    type: "vstack",
    padding: 12,
    background: "#1a1a2e",
    children: [
      { type: "text", content: "72°", fontSize: 36, fontWeight: "bold", color: "#fff" },
      { type: "progress", value: 0.7, tint: "#4CAF50" },
    ],
  },
}, "group.com.example.myapp", "weather");
if (outcome.reload.outcome === "throttled") {
  console.warn("reload delayed", outcome.reload.remainingSecs);
}

Source: guest-js/api/config.ts

setWidgetConfigFromPath()

async function setWidgetConfigFromPath(path: string, group?: string, widgetId = "default", skipReload = false, instance?: string): Promise<ApplyOutcome>

Read a WidgetConfig JSON file from disk and push it like setWidgetConfig.

Prefer this when the layout lives next to app resources instead of being built in code. path must be readable by the app process (absolute path or a resolved resourceDir() / app-data path). Network URLs are not supported.

Example

import { resourceDir, join } from "@tauri-apps/api/path";
import { setWidgetConfigFromPath } from "tauri-plugin-widgets-api";

const path = await join(await resourceDir(), "widgets", "weather.json");
await setWidgetConfigFromPath(path, "group.com.example.myapp", "weather");

Source: guest-js/api/config.ts

getWidgetConfig()

async function getWidgetConfig(group?: string, widgetId = "default", /** Read one placement's own config (no fallback to the widget-wide one). */ instance?: string): Promise<WidgetConfig | null>

Read the current widget UI configuration from the data store.

  • group: Widget group identifier. Omit to use plugins.widgets.appGroup (default group.<identifier>).
  • widgetId: Widget identity within the group (default "default").

Returns: The current WidgetConfig, or null if none has been set.

Source: guest-js/api/config.ts

reportReceipt()

async function reportReceipt(receipt: WidgetRenderReceipt): Promise<boolean>

Report that a renderer painted a config (desktop widget.html / tests). Native widgets write receipts themselves; this is for the host webview path.

Source: guest-js/api/diagnostics.ts

getWidgetDiagnostics()

async function getWidgetDiagnostics(group?: string): Promise<WidgetRenderReceipt[]>

Live widget instances that recently rendered for group.

Source: guest-js/api/diagnostics.ts

getWidgetTrace()

async function getWidgetTrace(group?: string, opts?: { since?: number }): Promise<WidgetTrace>

Host delivery journal + receipt history for group. Active in debug builds or when WIDGET_DEBUG=1.

Source: guest-js/api/diagnostics.ts

flushWidgetTrace()

async function flushWidgetTrace(): Promise<boolean>

Force-flush the in-memory journal to disk (desktop).

Source: guest-js/api/diagnostics.ts

widgetAction()

async function widgetAction(action: string, payload?: string, opts?: { widgetId?: string; group?: string }): Promise<boolean>

Trigger a widget-action event via the Rust plugin.

The Rust command broadcasts the event through app.emit(), so every window that called onWidgetAction() (or listen("widget-action", …)) will receive it — including the main application window.

  • action: Action identifier (matches ButtonElement.action).
  • payload: Optional extra string payload.

Source: guest-js/api/actions.ts

onWidgetAction()

async function onWidgetAction(callback: (data: WidgetActionPayload) => void): Promise<UnlistenFn>

Listen for widget-action events emitted by widget buttons.

  • callback: Called with the action payload each time a widget button with an action field is tapped.

Returns: A function to stop listening.

Example

import { onWidgetAction } from "tauri-plugin-widgets-api";

const unlisten = await onWidgetAction((data) => {
  console.log("Widget action:", data.action, data.payload);
  if (data.action === "refresh_data") {
    fetchLatestData();
  }
});

Source: guest-js/api/actions.ts

pollPendingWidgetActions()

async function pollPendingWidgetActions(group?: string): Promise<WidgetActionPayload[]>

Poll pending widget actions queued by native side (Android fallback path).

Source: guest-js/api/actions.ts

startWidgetUpdater()

async function startWidgetUpdater(builder: () => WidgetConfig | Promise<WidgetConfig>, /** Omit to use `plugins.widgets.appGroup`. */ group?: string, widgetId = "default", options?: { /** Tick interval in ms. Use `0` for a one-shot call (no periodic updates). Default: `5000`. */ intervalMs?: number; /** Call `builder` immediately before starting the interval. Default: `true`. */ immediate?: boolean; /** Also call `reloadAllTimelines()` after each tick. Default: `false`. * Backend throttles to once per 15 min on iOS/macOS. */ reload?: boolean; /** Subscribe to `widget-action` events for the lifetime of this updater. * The listener is automatically removed when the returned stop function is called. */ onAction?: (action: string, payload?: string) => void; }): Promise<() => void>

Start a periodic widget updater that calls builder on a fixed interval, sends the returned config to the native widget, and optionally reloads widget timelines.

This is a convenience wrapper around setInterval + setWidgetConfig + reloadAllTimelines so you don't have to write boilerplate timers.

Important (iOS/macOS): Apple enforces a daily widget reload budget (~40-70 reloads/day). The Rust backend throttles reloadAllTimelines() to at most once every 15 minutes. For frequent data updates, set reload: false (the default) — desktop webview widgets update instantly via events without counting against the budget.

  • builder: Called every intervalMs. Return the new WidgetConfig. May be async.
  • group: App Group / SharedPreferences group identifier.
  • options: Optional settings.
  • options.intervalMs: Update interval in milliseconds (default 5000). For native mobile widgets, consider using a longer interval (60000+) to avoid wasted work.
  • options.immediate: If true, run the builder immediately before the first interval tick (default true).
  • options.reload: If true, call reloadAllTimelines() after each update so native widgets refresh (default false). Set to true for native widgets; leave false for desktop-only. Note: backend throttles this to once per 15 min on iOS/macOS to respect the budget.

Returns: A stop() function. Call it to clear the timer.

Example

import { startWidgetUpdater } from "tauri-plugin-widgets-api";

const stop = await startWidgetUpdater(
  () => ({
    small: {
      type: "vstack", padding: 12, background: "#1a1a2e",
      children: [
        { type: "text", content: new Date().toLocaleTimeString(),
          fontSize: 24, fontWeight: "bold", color: "#fff" },
      ],
    },
  }),
  "group.com.example.myapp",
  "clock",
  {
    intervalMs: 60_000,
    reload: true,
    onAction: (action, payload) => {
      console.log("Widget action:", action, payload);
    },
  },
);

// later — stop updating and action listener:
stop();

Source: guest-js/api/updater.ts

getActiveWidgets()

async function getActiveWidgets(group?: string): Promise<ActiveWidget[]>

List placed widgets. Exact on Android (AppWidgetManager) and iOS (WidgetCenter); on desktop: open widget windows plus placements that rendered in the last 48 h (macOS WidgetKit, Windows Widgets Board).

Source: guest-js/api/instances.ts

setWidgetData()

async function setWidgetData(widgetId: string, data: unknown, options: { instance?: string; group?: string; skipReload?: boolean } = {}): Promise<boolean>

Values for {{data.path}} placeholders, without resending the layout. Pass null to clear. Layers: config.data < this < the widget's own source fetch.

Example

await setWidgetConfig({ small: { type: "text", content: "{{data.temp}}°" } }, undefined, "weather");
await setWidgetData("weather", { temp: 21 });

Source: guest-js/api/instances.ts

setWidgetState()

async function setWidgetState(widgetId: string, patch: Record<string, unknown> | null, options: WidgetStateOptions = {}): Promise<Record<string, unknown>>

Change a widget's local state ({{state.…}}, config state defaults) the way a set tap does: "$toggle", "$inc", "$dec", null removes a key (the default shows again), other values are stored. patch: null clears the stored state. Resolves with the merged state; the app also gets widget-state-changed {widgetId, instance, state}.

Example

await setWidgetState("tasks", { tab: "today", count: "$inc" });

Source: guest-js/api/instances.ts

getWidgetState()

async function getWidgetState(widgetId: string, options: Omit<WidgetStateOptions, "skipReload"> = {}): Promise<Record<string, unknown>>

A widget's merged local state: config state defaults, then what taps and setWidgetState stored (the placement's own over the widget's).

Source: guest-js/api/instances.ts

setWidgetInstances()

async function setWidgetInstances(widgetId: string, instances: WidgetInstanceOption[], group?: string): Promise<boolean>

Choices the user picks from per placement. iOS / macOS: the Edit Widget sheet of a widget built with TauriInstanceWidget / TauriInstanceProvider. The chosen id is the placement's instance.

Source: guest-js/api/instances.ts

registerActivityTemplate()

async function registerActivityTemplate(name: string, layout: Partial<Omit<ActivityContent, "id" | "template" | "data">> | Record<string, unknown> | null, group?: string): Promise<boolean>

Store a live activity layout on the device (shared store / App Group) under name. layout takes the ActivityContent layout fields (layout, lockScreen, compactLeading, islandCenter, title, …) with {{data.…}}, when, repeat; activities started with template: name then send only data. null removes it.

Example

await registerActivityTemplate("ride", {
  title: "Driver {{data.driver}}",
  lockScreen: { type: "text", content: "Arrives in {{data.eta}} min" },
});
await startActivity({ id: "ride-42", template: "ride", data: { driver: "Ann", eta: 4 } });

Source: guest-js/api/activity.ts

startActivity()

async function startActivity(content: ActivityContent, group?: string): Promise<ActivityHandle>

Start a live activity, or update it when id already runs.

Source: guest-js/api/activity.ts

updateActivity()

async function updateActivity(content: ActivityContent, group?: string): Promise<boolean>

Replace the content of a running activity.

Source: guest-js/api/activity.ts

endActivity()

async function endActivity(id: string, dismissAfterMs?: number, options: EndActivityOptions = {}): Promise<boolean>

End an activity; dismissAfterMs keeps the last state visible that long (iOS, desktop).

Source: guest-js/api/activity.ts

onActivityState()

async function onActivityState(cb: (e: ActivityStateEvent) => void): Promise<() => void>

Activity state changes from the native side (activity-state; no-op where none).

Source: guest-js/api/activity.ts

onActivityContent()

async function onActivityContent(cb: (e: ActivityContentEvent) => void): Promise<() => void>

Activity content changes from the native side (activity-content, e.g. push updates).

Source: guest-js/api/activity.ts

getWidgetPushToken()

async function getWidgetPushToken(group?: string): Promise<string | null>

WidgetKit push token (hex) for server-driven widget reloads; null where none exists.

Source: guest-js/api/activity.ts

getActivityPushToStartToken()

async function getActivityPushToStartToken(): Promise<string | null>

iOS 17.2+ push-to-start token (hex): your server can start a Live Activity with it (APNs event: "start", attributes-type: "TauriActivityAttributes", attributes: {id, group}, content-state: {json: "<ActivityContent JSON>"}). null on other platforms or before iOS issued one; changes arrive via onActivityTokens.

Source: guest-js/api/activity.ts

canPromoteActivities()

async function canPromoteActivities(): Promise<boolean>

Android 16+: whether activity notifications may show as Live Updates (status-bar chip, lock screen). true where no such gate exists (iOS, desktop, older Android).

Source: guest-js/api/activity.ts

openActivityPromotionSettings()

async function openActivityPromotionSettings(): Promise<boolean>

Android: open the system screen that allows Live Updates for this app; false if none.

Source: guest-js/api/activity.ts

onActivityTokens()

async function onActivityTokens(cb: (e: ActivityTokenEvent) => void): Promise<() => void>

Subscribe to Live Activity token changes (iOS only; a no-op elsewhere).

Source: guest-js/api/activity.ts

listActivities()

async function listActivities(): Promise<string[]>

Ids of running activities this app started.

Source: guest-js/api/activity.ts

Types

PLUGIN_ID

Shared plugin invoke prefix.

const PLUGIN_ID = "plugin:widgets";

WidgetWindowConfig

Configuration for creating a desktop widget window.

PropertyTypeDescription
labelstringUnique window label (e.g. "cpu-widget"). Used to reference the window later.
url?stringFrontend route to load. When omitted (or empty) the plugin serves its built-in widget renderer automatically — no extra files needed. Set to a path (e.g. "/widget.html") only if you want to use your own custom renderer.
widthnumberWindow width in logical pixels.
heightnumberWindow height in logical pixels.
x?numberX position on screen (pixels from left).
y?numberY position on screen (pixels from top).
alwaysOnTop?booleanKeep above all other windows. Default: false.
skipTaskbar?booleanHide from taskbar / dock. Default: true.
group?stringWidget group identifier. Required when using the built-in renderer — tells it which config to load via getWidgetConfig. Ignored when a custom url is provided.
widgetId?stringWidget identity within the group. Required for the built-in renderer.
instance?stringPlacement id: the built-in renderer reads config:{widgetId}#{instance} first, fills {{instance}}, and getActiveWidgets reports it. Default: the window label.
size?"small" | "medium" | "large"Size family the built-in renderer should display: "small", "medium", or "large". Defaults to "small".
layer?WidgetWindowLayerStacking layer. Default: "top" when alwaysOnTop, else "desktop" on Linux and "normal" on macOS / Windows. "desktop": X11 DESKTOP type, Wayland layer-shell Background, macOS desktop level, Windows behind the desktop icons.
clickThrough?booleanLet clicks pass through to whatever is below. Default false.
focusable?booleanWhether the window can take keyboard focus. Default true.
allWorkspaces?booleanShow on every virtual desktop / Space. Default: true for the desktop layer.
shadow?booleanSystem window shadow (macOS / Windows).
effects?"vibrancy" | "mica" | "acrylic" | "blur"Backdrop material hint (needs a transparent window; ignored on Linux).
placement?WidgetPlacementPlace relative to a monitor's work area instead of x / y.
rememberPosition?booleanRemember where the user moved the window (per label) and reopen it there while that spot is on a connected monitor. Default true.

WidgetWindowLayer

Stacking layer of a desktop widget window.

type WidgetWindowLayer = "normal" | "top" | "bottom" | "desktop";

WidgetPlacement

Monitor-relative placement for WidgetWindowConfig.placement.

PropertyTypeDescription
monitor?number | stringMonitor index (availableMonitors order) or name. Default: primary.
anchor?| "top-left" | "top" | "top-right" | "left" | "center" | "right" | "bottom-left" | "bottom" | "bottom-right"Work-area corner / edge. Default "top-left".
offsetX?numberLogical px inward from the anchored vertical edge. Default 0.
offsetY?numberLogical px inward from the anchored horizontal edge. Default 0.

SkipReason

Why a config write was skipped.

type SkipReason =
  | { reason: "unchanged"; hash: number }
  | { reason: "noInstances" }
  | { reason: "transportUnavailable"; name: string };

ReloadOutcome

Result of a native WidgetKit / AppWidget reload attempt.

type ReloadOutcome =
  | { outcome: "ok" }
  | { outcome: "throttled"; remainingSecs: number }
  | { outcome: "skipped"; why: string }
  | { outcome: "failed"; error: string };

ApplyOutcome

Full result of setWidgetConfig. Never treat success as “reload happened”.

PropertyTypeDescription
writtenbooleantrue when store bytes changed and were written.
reloadReloadOutcome
transportsstring[]Transport names that received the map (empty when not written).
skip?SkipReason

SkippedElement

Element the renderer skipped, with reason.

PropertyTypeDescription
typestring
reasonstring

WidgetRenderReceipt

Cross-platform render receipt (diagnostics — not a critical path).

PropertyTypeDescription
widgetIdstring
groupstring
instancestring
noncenumber
size?string
theme?string
schema?number
sourcestringprefs | state | appgroup | defaults | container | push | pull
trigger?stringreload | timeline | action | added | resize | snapshot
rendered?string[]
skipped?SkippedElement[]
tsnumber

TraceEvent

One host journal entry (WIDGET_DEBUG / debug builds).

type TraceEvent =
  | {
      kind: "configSet";
      widgetId: string;
      nonce: number;
      bytes: number;
      changed: boolean;
      skip?: { reason: "unchanged"; hash: number } | { reason: "noInstances" } | {
        reason: "transportUnavailable";
        name: string;
      };
    }
  | {
      kind: "write";
      transport: string;
      ok: boolean;
      durationMs: number;
      error?: string;
    }
  | { kind: "reload"; performed: boolean; reason: ReloadOutcome }
  | { kind: "poll"; count: number }
  | {
      kind: "render";
      instance: string;
      nonce: number;
      source: string;
      trigger: string;
      lagMs: number;
      skipped: SkippedElement[];
    };

TraceEntry

PropertyTypeDescription
tsnumber
kindTraceEvent["kind"]
[key: string]: unknown

WidgetTrace

PropertyTypeDescription
enabledboolean
eventsTraceEntry[]
receiptsWidgetRenderReceipt[]

WidgetActionPayload

Payload delivered by the widget-action event.

PropertyTypeDescription
actionstringThe action identifier from the button config.
payload?string | nullOptional extra data (e.g. serialized JSON from the widget). null when the widget sent none.
ts?numberUnix epoch ms when the action was enqueued / emitted.
widgetId?stringWidget identity that emitted the action.
group?stringApp group / prefs namespace.

ActiveWidget

A widget placed right now on a home screen, desktop or Widgets Board.

PropertyTypeDescription
widgetIdstringLogical widget id (WidgetKit kind / config widgetId).
instance?stringPlacement id: Android appWidgetId, the Apple Edit Widget choice, a window instance / label, a Widgets Board id. Absent when the placement has none.
size?stringsmall | medium | large when known.
lastSeenMs?numberUnix ms of the last render, when known from render receipts.

WidgetInstanceOption

A choice in the Apple Edit Widget sheet (e.g. a city).

PropertyTypeDescription
idstringPlacement id: {{instance}}, setWidgetConfig(…, instance).
titlestringText shown to the user.

WidgetStateOptions

Where a widget's local state lives: one placement (instance) or all of them.

type WidgetStateOptions = { instance?: string; group?: string; skipReload?: boolean };

ActivityAction

A button of a live activity; taps arrive as widget-action with widgetId: "activity.<id>".

PropertyTypeDescription
idstring
labelstring
systemName?stringIcon (SF Symbol; Material / emoji elsewhere).
url?stringOpen this deep link instead of queuing a widget-action.

ActivityContent

A live activity: iOS Live Activity (Lock Screen, Dynamic Island), Android ongoing notification (Live Update chip on Android 16), desktop always-on-top widget window. Without layout one is built from title / body / progress / endsAt / actions. The serialized request — including the layout the plugin builds when layout is omitted — must stay under 4 KiB (the ActivityKit limit, checked on every OS).

PropertyTypeDescription
idstringYour key (letters, digits, ., _, -).
title?stringRequired unless the template gives it.
body?string
progress?number0..1.
endsAt?numberUnix ms the countdown runs to.
icon?stringSF Symbol name (Material / emoji off Apple).
tint?stringHex accent color.
layout?WidgetElement
compactLeading?WidgetElement
compactTrailing?WidgetElement
minimal?WidgetElement
lockScreen?WidgetElementiOS Lock Screen layout when it should differ from layout.
islandLeading?WidgetElementExpanded Dynamic Island regions.
islandTrailing?WidgetElement
islandCenter?WidgetElement
keylineTint?stringHex colors: Dynamic Island keyline, Lock Screen background.
backgroundTint?string
subText?stringAndroid: notification sub text; Android 16 status-bar chip text (≤ 7 chars).
shortCriticalText?string
startedAt?numberUnix ms: a stopwatch counts up from here when endsAt is unset.
visibility?"public" | "private" | "secret"Android lock-screen visibility.
category?"progress" | "navigation" | "transport" | "workout" | "status" | "alarm" | "service" | "event"Android notification category.
actions?ActivityAction[]At most 3.
url?stringDeep link opened on tap.
staleAt?numberUnix ms after which the content counts as outdated (iOS).
push?booleaniOS: ask for an APNs token (pushToken, activity-token event).
template?stringName given to registerActivityTemplate: the device fills that layout with data, so the request (and its 4 KiB budget) carries only data. Fields set here override the template's.
data?Record<string, unknown>Values for {{data.…}} in the template.
relevanceScore?numberiOS: which of several activities the system shows first (higher wins).
alert?{ title: string; body: string; sound?: string }iOS: alert shown with this update (sound: a file in the app bundle).
timestamp?numberUnix ms the content was produced; an update older than the shown one is dropped.

ActivityHandle

PropertyTypeDescription
idstring
surfacestringios | android | desktop.
pushToken?string

EndActivityOptions

Options of endActivity.

PropertyTypeDescription
content?ActivityContentFinal content shown while the activity is dismissed.
dismissalPolicy?"default" | "immediate"immediate removes it at once; default lets the OS keep it a while (iOS: up to 4 h). dismissAfterMs wins over it.
group?string

ActivityStateEvent

Lifecycle of an activity reported by the OS.

type ActivityStateEvent = { id: string; state: "active" | "ended" | "dismissed" | "stale" | string };

ActivityContentEvent

Content the OS shows now (for example after a push update).

type ActivityContentEvent = { id: string; content: ActivityContent };

ActivityTokenEvent

Token events from iOS: per-activity APNs tokens and push-to-start token updates.

type ActivityTokenEvent =
  | { kind: "activity"; id: string; pushToken: string }
  | { kind: "pushToStart"; pushToStartToken: string };