Skip to main content
@capgo/capacitor-widget-kit UI & System Open source

Widget Kit Capacitor plugin

Build WidgetKit and Live Activity surfaces from Capacitor with SVG frames, timers, action hotspots, or full-native widget state sync

Install

bun add @capgo/capacitor-widget-kit bunx cap sync
npm, pnpm or yarn
  • npm install @capgo/capacitor-widget-kit
  • pnpm add @capgo/capacitor-widget-kit
  • yarn add @capgo/capacitor-widget-kit

Demo

Widget Kit demos

WidgetKit and Live Activity template controls shown as an animated WebP demo.

Source assets
Animated WidgetKit demo showing template widget state and controls driven from Capacitor
Widget template flow

Guide

How to use Widget Kit in Capacitor

Using @capgo/capacitor-widget-kit

@capgo/capacitor-widget-kit lets a Capacitor app drive WidgetKit and Live Activity experiences in two ways:

  • Render resolved SVG template surfaces with frame switching, tap hotspots, and pause/play timers.
  • Keep the widget fully native while the app and widget share JSON session state and async messages.

Install

bun add @capgo/capacitor-widget-kit
bunx cap sync

When To Use SVG Templates

Use SVG templates when the widget surface can be described as SVG. The app stores a template definition, the native bridge resolves placeholders, and widget taps can mutate state later.

Good fits include workout timers, delivery status cards, sports scores, or any compact UI where switching between named frames is enough.

import { CapgoWidgetKit } from '@capgo/capacitor-widget-kit';

const { activity } = await CapgoWidgetKit.startTemplateActivity({
  activityId: 'session-1',
  state: {
    title: 'Chest Day',
    frame: 'summary',
    restDurationMs: 90000,
  },
  definition: {
    id: 'workout-card',
    timers: [{ id: 'rest', durationPath: 'state.restDurationMs' }],
    actions: [
      {
        id: 'next-frame',
        frameMutations: [{ op: 'next', path: 'frame', surface: 'lockScreen' }],
      },
      {
        id: 'toggle-rest',
        timerMutations: [{ op: 'toggle', timerId: 'rest' }],
      },
    ],
    layouts: {
      lockScreen: {
        width: 100,
        height: 40,
        frameIdPath: 'state.frame',
        frames: [
          {
            id: 'summary',
            hotspots: [{ id: 'switch', actionId: 'next-frame', x: 0, y: 0, width: 100, height: 40 }],
            svg: `<svg viewBox="0 0 100 40"><text x="6" y="22">{{state.title}}</text></svg>`,
          },
          {
            id: 'timer',
            hotspots: [{ id: 'pause-play', actionId: 'toggle-rest', x: 0, y: 0, width: 100, height: 40 }],
            svg: `<svg viewBox="0 0 100 40"><text x="6" y="22">{{timers.rest.remainingText}}</text></svg>`,
          },
        ],
      },
    },
  },
});

Handle Widget Actions In The App

Widget actions are persisted as events. Read and acknowledge them when the app resumes or after a background sync step.

const { events } = await CapgoWidgetKit.listTemplateEvents({
  activityId: activity.activityId,
  unacknowledgedOnly: true,
});

for (const event of events) {
  console.log(event.actionId, event.state, event.timers);
}

await CapgoWidgetKit.acknowledgeTemplateEvents({ activityId: activity.activityId });

When To Use Full-Native Sessions

Use full-native sessions when the widget UI is better built directly in Swift, Kotlin, or Java. Capacitor still starts and stops the session, keeps shared state current, and queues work between app and widget code.

const { session } = await CapgoWidgetKit.startWidgetSession({
  widgetId: 'native-session-1',
  kind: 'workout-controls',
  state: { isRunning: true, selectedSetId: 'set-1' },
  metadata: { accent: '#00d69c' },
});

await CapgoWidgetKit.updateWidgetSession({
  widgetId: session.widgetId,
  merge: true,
  state: { isRunning: false },
});

Queue Async Work Between Widget And App

Messages can flow from app to widget or widget to app. They stay pending until acknowledged and completed.

const { message } = await CapgoWidgetKit.sendWidgetMessage({
  widgetId: session.widgetId,
  direction: 'widgetToApp',
  name: 'syncWorkoutSet',
  payload: { setId: 'set-1' },
  expectsResponse: true,
});

await CapgoWidgetKit.acknowledgeWidgetMessages({ messageIds: [message.messageId] });

await CapgoWidgetKit.completeWidgetMessage({
  messageId: message.messageId,
  response: { synced: true },
});

If the job fails, complete the message with an error:

await CapgoWidgetKit.completeWidgetMessage({
  messageId: message.messageId,
  error: 'Sync failed',
});

Stop Sessions Cleanly

await CapgoWidgetKit.endTemplateActivity({
  activityId: activity.activityId,
  state: { title: 'Workout complete', frame: 'summary' },
});

await CapgoWidgetKit.stopWidgetSession({
  widgetId: session.widgetId,
  state: { isRunning: false },
});

Native Setup Notes

For iOS WidgetKit and Live Activities, configure an App Group on the app and widget extension targets and set CapgoWidgetKitAppGroup in both Info.plist files. Interactive buttons require a widget extension that wires the plugin-provided native bridge and action intent.

Full Reference

Keep going from Using @capgo/capacitor-widget-kit

If you are using Using @capgo/capacitor-widget-kit to plan native plugin work, connect it with @capgo/capacitor-widget-kit for the implementation detail in @capgo/capacitor-widget-kit, Getting Started for the implementation detail in Getting Started, Capgo Plugin Directory for the product workflow in Capgo Plugin Directory, Capacitor Plugins by Capgo for the implementation detail in Capacitor Plugins by Capgo, and Adding or Updating Plugins for the implementation detail in Adding or Updating Plugins.

FAQ

Widget Kit plugin FAQ

How do I install the Widget Kit plugin in a Capacitor app?

Run "bun add @capgo/capacitor-widget-kit" (or "npm install @capgo/capacitor-widget-kit"), then run "bunx cap sync" so the iOS and Android projects pick up the native code. Import it from "@capgo/capacitor-widget-kit" in your app code.

Does @capgo/capacitor-widget-kit work with React, Vue and Angular?

Yes. Widget Kit is a Capacitor package, so it works with any web framework that runs inside Capacitor, including Ionic, React, Vue, Angular, Svelte and plain JavaScript.

Which Capacitor version does @capgo/capacitor-widget-kit support?

Capgo plugins follow Capacitor's major version: use the plugin major version that matches your Capacitor major version (for example plugin v8 with Capacitor 8). The compatibility table in the GitHub README lists the maintained versions.

Is @capgo/capacitor-widget-kit free and open source?

Yes. The source code is public on GitHub at https://github.com/Cap-go/capacitor-widget-kit/ and the package is free to install from npm. Bug reports and pull requests are welcome.

Can I update code that uses Widget Kit without an App Store review?

Installing or upgrading the plugin changes native code, so it needs a new store build. After that, JavaScript, HTML and CSS changes that call the plugin can ship instantly with Capgo live updates.

Ship Widget Kit changes without waiting for app review

Once the plugin is in your store build, Capgo live updates push your JavaScript, HTML and CSS changes to users in minutes.

Start with Capgo