Glassly Miniapp SDK betaThe SDK is in beta, so its APIs may change before general availability.Developing on Mentra Live? We recommend using the Glassly Bluetooth SDK.The developer tools are available in the Glassly App under Settings → Miniapp Developer Settings.Share feedback with an in-app bug report, on Discord, or by email at [email protected].
Every Glassly miniapp has two layers. Understanding the split is the key to the whole SDK: it determines where your code runs, what it can reach, and how the two halves communicate.

File layout

miniapp.json points at the built output of each layer:

The background layer

The host evaluates your background bundle inside a per-miniapp JavaScript context and calls your registerMiniapp handler once the connection is ready. This is where every session.* call lives.
src/background/index.ts
The background runs even when no UI is open. Register your subscriptions in the handler; they live for as long as the miniapp is enabled.
The background context is not a browser and not Node: it’s a bare JS engine (JavaScriptCore on iOS, QuickJS on Android). There’s no window, no DOM, and no module resolver at runtime, which is why build.ts bundles the SDK into your background output rather than leaving it external.

Background runtime APIs

Do not infer background support from what TypeScript or Bun accepts at build time. The background bundle targets a small, cross-platform runtime. Glassly currently provides these browser-like globals: Common browser and Node APIs are not available in the background, and the build rejects them by name with the source location and a supported alternative: Node built-ins (fs, path, child_process, and the rest) are rejected the same way. Put rendering, DOM work, and browser UI libraries in src/ui/. Put session.* calls, hardware subscriptions, durable state, and logic that must continue after the UI closes in src/background/. Exchange only serializable data through glassly.* / session.ui.*.
location and Blob are the two that surprise people: in the background session.location is the GPS module, not the browser URL object, and binary data belongs in session.blob.
If an AI coding agent introduces performance.now(), DOM access, or a Node API under src/background/, move that code to the UI or replace it with a supported primitive. For elapsed time in the background, use Date.now().Projects created with @glassly/create-miniapp also check background source and its imported shared files during bun run build. Common unsupported browser or Node APIs fail the build with the source location and a supported alternative.

The UI layer

The UI is a normal React app. It has zero direct native access: it reaches the glasses only by sending messages to its own background layer. It mounts inside <MiniappProvider> and must call glassly.ready() on boot so the host knows it’s mounted.
src/ui/main.tsx

Talking between layers

The two layers never share memory: they pass messages over a typed bus. You declare every channel once in src/shared/channels.ts; both halves import it, so names and payload shapes are enforced at compile time.
src/shared/channels.ts
From the UI, use the injected glassly global:
From the background, use session.ui:
The two sides are intentionally asymmetric: glassly.send from the UI buffers until the WebView calls ready(), while session.ui.send from the background drops silently when no WebView is open (there’s no one to receive it). There’s no runtime channel registry: channel names are opaque strings on the wire, validated only by TypeScript. See Interop & Actions for the separate, cross-miniapp RPC layer (session.actions).

Lifecycle

  1. Start: after installation, opening the miniapp, an Always On autostart, or an authorized background start spawns the background JS context and runs your registerMiniapp handler.
  2. UI opens: the user taps your tile; the host spawns a WebView, injects the glassly shim, and loads ui/index.html. The WebView calls glassly.ready(), and session.ui.onOpen fires in the background.
  3. UI closes: the user navigates away; the host destroys the WebView. The background context stays alive and session.ui.onClose fires.
  4. Stop / uninstall: the host tears down your subscriptions and kills the background context.
Manifest alwaysOn: true starts the miniapp at host launch and keeps its background alive when its app switcher card is dismissed. The wearer can override the default or explicitly stop it from the switcher’s Always On controls. For ordinary miniapps, dismissing the switcher card stops the miniapp. Keep durable state in storage so it can be restored on the next start.

Crash recovery

If your background layer crashes, the host restarts it automatically. Repeated crashes back off and eventually show the user a “try again” prompt, so aim to reach a stable state quickly on startup.

Next steps

The manifest

Declare entries, permissions, and hardware in miniapp.json.

The session

The background-side handle to every glasses capability.

The UI layer

React hooks, the capsule menu, and safe areas.

Interop & Actions

Let other miniapps (and Glassly AI) call yours.