Summary
session.glasses.onConnection() is typed as delivering ConnectionData:
export interface ConnectionData {
connected: boolean
modelName?: string
}
On Mentra Live the host delivers a ~40-field device status object with no top-level connected
and no modelName. Connection state is nested at connection.state, and the model is
deviceModel.
So data.connected is undefined — falsy — and any handler written against the published type takes
its disconnected branch on every event. The event fires roughly every 10 seconds, often twice, so
this is continuous rather than occasional.
TypeScript compiles cleanly throughout, which is what makes it expensive: the type is the thing that
is wrong, so there is no compile-time or runtime signal at all.
What the host actually sends
Logged verbatim from the handler (identifiers redacted):
{
"connection": { "state": "connected", "fullyBooted": true },
"deviceModel": "Mentra Live",
"batteryLevel": 81,
"charging": false,
"signalStrength": -58,
"bluetoothClassicConnected": true,
"micEnabled": true,
"voiceActivityDetectionEnabled": false,
"wifi": { "state": "connected", "ssid": "<redacted>", "localIp": "<redacted>" },
"hotspot": { "state": "disabled" },
"caseOpen": true, "caseRemoved": true, "caseCharging": false, "caseBatteryLevel": -1,
"headUp": false,
"androidVersion": "11",
"buildNumber": "<redacted>",
"mtkFirmwareVersion": "MentraLive_2026xxxx",
"besFirmwareVersion": "26.8.5.0",
"appVersion": "staging.20260808.*",
"controllerConnected": false, "controllerBatteryLevel": -1,
"...": "plus bluetoothMacAddress, serialNumber, otaVersionUrl, style, color, etc."
}
Impact
In our client the disconnect branch abandoned any capture in flight, so every wake was killed about
three seconds later:
09:11:31 listening (wake, +128000B pre-roll)
09:11:34 glasses disconnected — abandoning any capture in flight
09:11:34 glasses disconnected — abandoning any capture in flight
The glasses were connected the whole time at -58 dBm, and audio kept arriving throughout.
Reproduction
session.glasses.onConnection((data) => {
console.log(JSON.stringify(data)) // no `connected` key present
console.log(data.connected) // undefined, on every event
})
Suggested fix
Either make the host emit the documented shape, or update ConnectionData to describe what is
actually sent. If the wide status blob is intentional, a typed interface for it would be genuinely
useful — batteryLevel, wifi, headUp and caseOpen are all things an app would want and none
are currently reachable through a typed API.
Two smaller notes:
- The event is emitted about twice per tick, and roughly 5 times in quick succession at startup.
If that is intentional, it is worth documenting, since handlers that log or act on it need to
debounce.
onWifi documents that it "fires the current state on subscribe"; onConnection does not say
either way, and it appears to as well.
Environment
@mentra/miniapp 3.1.0-dev.27
- Device: Mentra Live, MentraOS app
staging.20260808.*, MTK firmware MentraLive_2026xxxx
Summary
session.glasses.onConnection()is typed as deliveringConnectionData:On Mentra Live the host delivers a ~40-field device status object with no top-level
connectedand no
modelName. Connection state is nested atconnection.state, and the model isdeviceModel.So
data.connectedisundefined— falsy — and any handler written against the published type takesits disconnected branch on every event. The event fires roughly every 10 seconds, often twice, so
this is continuous rather than occasional.
TypeScript compiles cleanly throughout, which is what makes it expensive: the type is the thing that
is wrong, so there is no compile-time or runtime signal at all.
What the host actually sends
Logged verbatim from the handler (identifiers redacted):
{ "connection": { "state": "connected", "fullyBooted": true }, "deviceModel": "Mentra Live", "batteryLevel": 81, "charging": false, "signalStrength": -58, "bluetoothClassicConnected": true, "micEnabled": true, "voiceActivityDetectionEnabled": false, "wifi": { "state": "connected", "ssid": "<redacted>", "localIp": "<redacted>" }, "hotspot": { "state": "disabled" }, "caseOpen": true, "caseRemoved": true, "caseCharging": false, "caseBatteryLevel": -1, "headUp": false, "androidVersion": "11", "buildNumber": "<redacted>", "mtkFirmwareVersion": "MentraLive_2026xxxx", "besFirmwareVersion": "26.8.5.0", "appVersion": "staging.20260808.*", "controllerConnected": false, "controllerBatteryLevel": -1, "...": "plus bluetoothMacAddress, serialNumber, otaVersionUrl, style, color, etc." }Impact
In our client the disconnect branch abandoned any capture in flight, so every wake was killed about
three seconds later:
The glasses were connected the whole time at -58 dBm, and audio kept arriving throughout.
Reproduction
Suggested fix
Either make the host emit the documented shape, or update
ConnectionDatato describe what isactually sent. If the wide status blob is intentional, a typed interface for it would be genuinely
useful —
batteryLevel,wifi,headUpandcaseOpenare all things an app would want and noneare currently reachable through a typed API.
Two smaller notes:
If that is intentional, it is worth documenting, since handlers that log or act on it need to
debounce.
onWifidocuments that it "fires the current state on subscribe";onConnectiondoes not sayeither way, and it appears to as well.
Environment
@mentra/miniapp3.1.0-dev.27staging.20260808.*, MTK firmwareMentraLive_2026xxxx