Skip to main content
Use the optional @feedbackloop/react/tauri entry point from the MIT-licensed 0.1.1 package in a React 19/Tauri 2 app. This guide includes the root, updater adapter and capabilities; no private repository example is required. Your app retains update eligibility, native handles, persistence, installation and restart. Publish a release note with the exact native app version, including build metadata.

Install and mount the host

The optional native entry point opens reusable release-reader and update windows. It reads the app name and installed version through Tauri, rather than the frontend package version. Mount the same ReleaseNotesHost root before your app’s startup providers and router in each app window. Keep the main window’s root mounted, including while it is hidden; it remains the sole owner of update callbacks and preferences. SDK child windows use the same entry point and are handled automatically. Keep app startup effects and background update checks in the main window. Install the published SDK and official Tauri 2 JavaScript peers in your existing React 19/Tauri 2 application:
Add the corresponding Rust store/opener plugins from your src-tauri directory:
Register them on your existing Tauri builder:
App and flushAppState are your application modules. The flush must await real database/document/media writes and reject when they cannot be saved; do not substitute an empty function. Keep appUpdater stable across React renders. The default host label is main; only supply hostWindowLabel when your existing sole owner has a different label. If you override it, change the isMain guard and the host capability’s windows label to that same value so the updater owner initializes in the correct window. SDK child detection prevents <App /> from rendering in SDK windows, but module imports still execute. Keep native resource construction behind the main-window guard above, and keep startup/background-check effects in main. Adapt owner.dispose() to your app’s updater shutdown lifecycle. Main owns cleanup; closing Settings must not dispose its updater.

Consumer-owned updater

The native entry point exports the complete types below. check() decides whether a candidate is eligible, including any app-specific rollout or rollback policy. install() owns the exact-candidate guard, app-state flush, installation and automatic restart. notes is optional plain-text updater content; published Feedback Loop Markdown remains the primary release document.
The adapter flushes before installation and again immediately before restart so edits made during download are saved. A failed final flush prevents restart and retains the installed version for retry without another download or installation. The flush must drain real writes and reject on save conflicts. After installation, check() returns the retained pending-restart version without acquiring a new native handle; closing a failed restart window and choosing Check now therefore preserves the restart retry. The root above uses the following consumer-owned app-updater.ts adapter for Tauri’s official updater and process plugins. Supply flushAppState from your app’s persistence layer, and release the returned owner through your app’s updater shutdown path. Construct this adapter only in main; ordinary secondary windows receive the harmless callbacks shown above, which the SDK does not invoke there. Install and register the optional app-owned updater/process plugins as well as the SDK’s store/opener requirements:
Configure your own updater endpoint, matching public signing key and update artifacts in Tauri. No private signing key belongs in the frontend. The example adapter deliberately omits cancel: official downloadAndInstall does not expose supported cancellation. The SDK hides Cancel, and closing the progress window leaves installation running.
Keep native update handles in this adapter. If your app already checks in the background, pass its candidate to useReleaseNotes().notifyUpdateAvailable(candidate); the SDK does not start another checker. notifyUpdateAvailable() respects the skipped exact version. The Check now control in ReleaseNotesSettings ignores a previously skipped version. useReleaseNotes() in 0.1.0 exposes only open() and notifyUpdateAvailable(); it has no public manual-check method. Installation failures stay retryable; the sample also retains a successful-install/pending-relaunch state so relaunch can be retried without reinstalling.

Manual checks from app menus

Published SDK 0.1.1 includes useReleaseNotes().checkForUpdates(): Promise<void>, which exposes the same manual action as Check now for an app menu or tray bridge. It checks through the main updater, bypasses Skip, and returns focus to the requesting Settings window after the result closes. 0.1.0 does not include this method. A fresh Settings caller waits up to 15 seconds for the authenticated main connection before sending its request. Catch rejected connection or transport promises in the app action and allow retry. Failed checks appear in the SDK update window with Try again. Installation or restart failures keep the Install update button available to retry the app-owned operation. If one tray request arrives through both a query parameter and a native event, coalesce that delivery in your app before calling the action. Keep main mounted; reloading its WebView still requires reopening connected windows. Use the same app-owned updater owner for background and Settings checks so a notified candidate refers to the retained handle that install() will validate. Inside the host, add the supplied Updates settings and a menu action. ReleaseNotesSettings takes no props and includes Show changelog after each update, What’s new and Check now controls:

Existing secondary settings window

If your app already opens a separate settings window, mount the same root in that window and render ReleaseNotesSettings in its Updates tab. The settings controls connect to the main host; they stay disabled until its current state arrives. The secondary window does not run the updater callbacks or persist preferences. Keep the main root mounted even when the settings window is closed. The reader and update prompt return focus to the settings window that opened them when closed. The main window can remain hidden. A single-window app uses the normal host setup without this additional capability. Add this optional local capability, replacing settings-window with your existing window’s actual label:
Keep this capability local, without remote origins. Retain your settings window’s existing app permissions separately; the release integration adds only these event permissions there. Store, window-creation and updater permissions belong to the main host.

Native capabilities

Create separate local files under src-tauri/capabilities/. These exact labels match the default main host and SDK-created children. Do not grant updater/store access through a wildcard window capability. Review overlapping existing capabilities: adding a narrow file does not revoke a broader grant elsewhere. release-notes-host.json below includes the official updater/process permissions used by this guide’s adapter. Remove those three plugin permissions if your app uses a different app-owned updater. Window hiding is an app-owned action, not an SDK requirement; retain core:window:allow-hide separately if your own tray or Settings code needs it.
release-notes-children.json permits only presentation events, self-close and HTTP(S) links:
Keep these capabilities local, without remote origins. Preserve permissions your existing app features require, while keeping SDK preferences and updater resources main-owned. An existing secondary Settings window uses the event-only capability above; it receives no SDK updater/store permissions.

Theme and content security policy

Pass the app’s current system, light or dark preference to the main host’s theme prop. Open SDK windows update when it changes; system tracks operating-system changes live. In embedded Settings, application variables --background, --foreground, --muted-foreground, --border, --primary and --primary-foreground override the fallback palette. Import @feedbackloop/react/styles.css once in the root; no Tailwind setup is required. If your app defines a CSP, add https://feedbackloop.page to connect-src, alongside existing Tauri IPC and app-owned updater endpoints. Permit the API origin and the actual redirected storage/CDN and external Markdown image origins in img-src. An API-origin-only image policy can block the final signed-image redirect. Keep your existing restrictions; do not allow arbitrary remote pages access to native capabilities.

After-update behavior

Settings persist only whether to show notes after an update, the acknowledged installed version and the skipped candidate version. First launch establishes the current version without showing old notes. A later installed upgrade opens its exact published note after it renders successfully; a failure remains retryable. The same full installed version and downgrades stay quiet; different build metadata at equal SemVer precedence counts as a new installed release. Missing or offline exact-version publication defers acknowledgement and retries on host focus/connectivity. Both windows follow the selected theme, and system changes update open windows.

Recovery and release checks

A startup error usually means a missing Rust plugin or local app/event/window/store permission. Verify registration and exact labels, and review all overlapping capabilities. If the app has a separate Settings window, main must remain mounted even when hidden. Keep app boot, account/editor effects and background checkers main-only; SDK child windows must not start them. During development, reloading only the main WebView replaces its private connection state. Close and reopen existing Settings windows afterward. A full app restart creates a fresh host and preferences connection. Test an installation failure and a relaunch failure: the adapter must preserve retryability, reject stale candidate versions, and finish a real save before installation. Closing the progress window does not cancel the app-owned install. Omit cancel unless your own updater truly supports cancellation. Before distributing your app, test full history and an exact published native version, existing secondary Settings, return focus with hidden main, live themes, preferences across restart, offline/reconnect, and first-launch baseline. Demonstrate automatic after-update notes using two SDK-enabled builds; the first SDK launch cannot infer the previous installed version. Complete real signed installer replacement, persistence flush and automatic relaunch acceptance on every OS you ship. SDK macOS/Windows/Linux native fixture CI exercises real windows with simulated updates; it does not prove your app’s installer. Missing exact notes stay retryable rather than acknowledging a saved copy. Publishing notes never uploads an app binary. See the React reader for embedded browser use and the HTTP API for the wire and image contract.