The Mentra Bluetooth SDK exposes the same core glasses lifecycle across Android, iOS, and React Native:
  • Scan for a supported glasses model.
  • Connect to a discovered Device or an app-restored default device.
  • Read typed lifecycle state through the public surface for your platform.
  • Subscribe to typed hardware events.
  • Send display, camera, stream, audio, Wi-Fi, hotspot, LED, and settings commands where supported by the connected model.

Packages And Imports

PlatformInstall packageImport
Androidcom.mentraglass:bluetooth-sdkimport com.mentra.bluetoothsdk.*
iOSMentraBluetoothSDK Swift packageimport MentraBluetoothSDK
React Native / Expo@mentra/bluetooth-sdkimport BluetoothSdk, {DeviceModels} from '@mentra/bluetooth-sdk'
React Native hooks@mentra/bluetooth-sdkimport {useMentraBluetooth} from '@mentra/bluetooth-sdk/react'
React Native photo receiver@mentra/bluetooth-sdkimport MentraPhotoReceiver from '@mentra/bluetooth-sdk/photo-receiver'
Only documented imports are part of the supported app developer API. Undocumented package subpaths or symbols with a leading underscore can change without notice.

Lifecycle

import {useBluetoothEvent, useMentraBluetooth} from '@mentra/bluetooth-sdk/react';

function DeviceScreen() {
  const mentra = useMentraBluetooth();
  useBluetoothEvent('button_press', (event) => {
    console.log(event.buttonId, event.pressType);
  });

  console.log(mentra.glasses.connection.state);
}
Keep one SDK instance per active app session. The SDK owns Bluetooth connection state, native event delivery, and cleanup. Your app owns user identity, UI state, and whether a default device record is persisted across app restarts.

Connection

const devices = await BluetoothSdk.scan(DeviceModels.MentraLive, {
  timeoutMs: 10_000,
  onResults: (nextDevices) => renderDevicePicker(nextDevices),
});

const device = await chooseDevice(devices);
await BluetoothSdk.connect(device, {saveAsDefault: false});

await BluetoothSdk.setDefaultDevice(device);

const defaultDevice = await BluetoothSdk.getDefaultDevice();
await BluetoothSdk.connectDefault();
await BluetoothSdk.clearDefaultDevice();

await BluetoothSdk.cancelConnectionAttempt();
await BluetoothSdk.disconnect();
await BluetoothSdk.forget();
Prefer connecting to a Device returned by SDK scan callbacks. If your app wants connectDefault() to work after restart, persist a small default-device record in app storage and restore it with setDefaultDevice() before calling connectDefault(). Use scan() for user-facing device pickers. The progressive result callback is for UI: render the nearby-device list every time it changes during scanning. The returned final result is for control flow: after the timeout/completion, choose a device from the last list and connect. In multi-device environments, do not auto-connect to the first nearby glasses; present an explicit picker.

Device Identity

Device.id is the stable app-facing key for a scan result, within the limits of the platform identifier available to the SDK. Use it as a list key, selected-device key, and persisted default-device key. Do not parse id for model, name, or address information. Use the typed fields instead:
FieldMeaning
modelSupported glasses family, such as Mentra Live or G2.
nameBluetooth/display name reported during scan.
address / identifierPlatform device handle when available. Android commonly provides a Bluetooth address. iOS commonly provides a CoreBluetooth identifier. React Native exposes this value as address.
rssiOptional signal strength from scan results. It may be undefined at first discovery and appear in a later scan update when the platform reports RSSI metadata.
When the platform does not provide an address or identifier, the SDK falls back to a model:name key. Do not require rssi for picker rows. Use SDK-provided stable discovery order by default, and treat RSSI as supplemental signal-strength metadata when it is present.

Status

import {useMentraBluetooth} from '@mentra/bluetooth-sdk/react';

const mentra = useMentraBluetooth();
React Native exposes mentra.glasses.connection as a discriminated union:
type GlassesConnectionStatus =
  | {state: 'disconnected'}
  | {state: 'scanning'}
  | {state: 'connecting'}
  | {state: 'bonding'}
  | {state: 'connected'; fullyBooted: boolean};
Use mentra.glasses.connection.state for link-layer progress. fullyBooted only exists when state === 'connected'. The hook exposes the React app state as glasses, sdk, and scan.
Status snapshots are safe to read at any time. Treat command success as “command accepted”; keep UI state derived from status callbacks or hook state. Public status is grouped the same way across platforms:
FieldMeaning
glassesConnected-glasses runtime state. Includes connection/readiness, connected device identity, battery, firmware, Wi-Fi, hotspot, and signal metadata when connected.
sdkPhone-side SDK runtime state. Includes default device, gallery mode, microphone route, mic ranking, Wi-Fi scan results, scan activity, system mic availability, other Bluetooth audio status, and recent SDK log lines.
scanUser-facing scan state. Includes whether a scan is active, whether controller scanning is active, and the stable-order discovered Device[] list.
Use glasses.connected / mentra.glasses.connected before reading connected-only fields. Native Android uses GlassesRuntimeState.Connected; native iOS uses GlassesRuntimeState.connected(...); React Native exposes mentra.glasses with the same grouped concepts in React-friendly objects.

React Native Public Surface

These are the supported React Native app developer entrypoints:
AreaMethods
Status and subscriptionsuseMentraBluetooth, useBluetoothScan, and useBluetoothEvent for React components; addListener is available as the lower-level non-React subscription API
Default devicegetDefaultDevice, setDefaultDevice, clearDefaultDevice
Connectionscan, startScan, stopScan, connect, connectDefault, cancelConnectionAttempt, disconnect, forget
DisplaydisplayText, clearDisplay, showDashboard, setDashboardPosition, setHeadUpAngle, setScreenDisabled
Wi-Fi and hotspotrequestWifiScan, sendWifiCredentials, forgetWifiNetwork, setHotspotState
Camera and galleryrequestPhoto, queryGalleryStatus, setGalleryModeEnabled, setButtonPhotoSettings, setButtonVideoRecordingSettings, setButtonCameraLed, setButtonMaxRecordingTime, setCameraFov, startVideoRecording, stopVideoRecording
StreamingstartStream, stopStream
AudiosetMicState, setVoiceActivityDetectionEnabled, setPreferredMic, setOwnAppAudioPlaying, getGlassesMediaVolume, setGlassesMediaVolume
LED, version, and OTArgbLedControl, requestVersionInfo, checkForOtaUpdate, startOtaUpdate, retryOtaVersionCheck
React Native helper exports include DeviceModels, isConnectedGlassesConnectionStatus, isReadyGlassesConnectionStatus, isBusyGlassesConnectionStatus, isConnectedWifiStatus, and isEnabledHotspotStatus. The React subpath exports useMentraBluetooth, useBluetoothScan, and useBluetoothEvent. For React Native status UI, use useMentraBluetooth() from @mentra/bluetooth-sdk/react. It returns mentra.glasses, mentra.sdk, and mentra.scan for connection, battery, Wi-Fi, hotspot, scan, and SDK runtime state. Important defaults:
  • scan(model, options) reports progressive results through options.onResults, resolves with the final matching Device[], and times out after 15 seconds unless options.timeoutMs is set.
  • connect and connectDefault default saveAsDefault and cancelExistingConnectionAttempt to true.
  • displayText(text, x, y, size) defaults to x = 0, y = 0, and size = 24.
  • setMicState(enabled) defaults to glasses microphone on, transcript events off, and LC3 events off. Microphone audio events are continuous while capture is enabled. Use setVoiceActivityDetectionEnabled(...) for glasses-side Voice Activity Detection; voice_activity_detection_status reports whether it is enabled, and speaking_status reports speaking/not-speaking when supported. Microphone audio events include the latest voiceActivityDetectionEnabled value.
  • requestPhoto({authToken, ...}) omits the Authorization header when authToken is null or empty.
  • requestPhoto({exposureTimeNs, ...}) uses auto exposure when exposureTimeNs is omitted or null; pass a positive nanosecond value for one-shot manual exposure.
  • requestPhoto({exposureTimeNs, iso, ...}) uses iso only when exposureTimeNs enables one-shot manual exposure. Omit iso / pass null for auto ISO selection.
  • setCameraFov({fov, roiPosition}) clamps fov to 62-118 degrees and roiPosition to 0 center, 1 bottom, or 2 top. The "narrow" (82°), "standard" (102°), and "wide" (118°) presets are also accepted and map to center ROI. On Mentra Live this persists the setting and restarts the camera for about 5 seconds before the next capture should run. Treat FOV as a framing/ROI control; output resolution and effective detail can vary by capture path, firmware, and camera mode.
  • startStream optional video and audio configs are omitted unless supplied, so the connected glasses use their model defaults. The SDK sends stream keep-alives automatically and reports timeout/error state through stream_status.
  • Photo capture, video recording, and streaming always enable the camera light as a privacy indicator.
Mentra Live has a gallery mode for the right action button. When gallery mode is enabled, a short press takes a photo, a long press starts video recording, and a short press stops the active video recording. Button and touch events are still reported to the SDK. Use setGalleryModeEnabled(true) to enable local button capture, and setGalleryModeEnabled(false) to report button events without triggering local gallery capture while the glasses are connected. The SDK can also configure the capture settings used by gallery mode:
SettingAPI
Photo sizesetButtonPhotoSettings(...)
Video resolution and frame ratesetButtonVideoRecordingSettings(width, height, fps)
Maximum video lengthsetButtonMaxRecordingTime(minutes)
Camera field of viewsetCameraFov(...)
Camera LED preferencesetButtonCameraLed(...)

Common Commands

AreaCommands
DisplaydisplayText, clearDisplay, showDashboard
Connectionscan, startScan, stopScan, connect, connectDefault, disconnect, forget
Wi-Fi and hotspotrequestWifiScan, sendWifiCredentials, forgetWifiNetwork, setHotspotState
CamerarequestPhoto, gallery mode, button photo settings, button video settings, camera field of view
StreamingstartStream, stopStream
AudiosetMicState, Voice Activity Detection setting and events, audio callbacks, local transcription, media volume
SettingsBrightness, dashboard position, head-up angle, screen disabled, gallery mode
LEDsrgbLedControl on supported glasses
SystemrequestVersionInfo, checkForOtaUpdate, startOtaUpdate, retryOtaVersionCheck
Mentra Live has camera, microphone, and speaker hardware, but no display. G2 has display and microphone hardware, but no camera or speaker. Gate UI for display, camera, and speaker features by the connected model.

OTA Updates

Mentra Live OTA is glasses-owned. The SDK exposes the same command and event semantics used by the MentraOS app:
APIGlasses commandPurpose
checkForOtaUpdate()ota_query_statusAsk the glasses to report update availability or current progress.
startOtaUpdate()ota_startStart OTA after your app presents the update and the user accepts it.
retryOtaVersionCheck()ota_retry_version_checkRe-run the glasses-side version check after a known clock-skew/TLS failure.
React Native receives ota_update_available, ota_start_ack, and ota_status events. Android listeners receive onOtaUpdateAvailable, onOtaStartAck, and onOtaStatus. iOS delegates receive .otaUpdateAvailable, .otaStartAck, and .otaStatus through BluetoothEvent. OTA requires Mentra Live glasses firmware that supports the ASG OTA protocol and network access from the glasses. During install, normal BLE traffic can be interrupted and the glasses may restart; keep the app connected and avoid sending unrelated commands until ota_status.status is complete or failed.

Events

React Native components should use useBluetoothEvent() for hardware events. The hook keeps the callback typed and removes the native subscription when the component unmounts. Native apps receive the same event categories through listener/delegate methods:
import {useBluetoothEvent} from '@mentra/bluetooth-sdk/react';

export function HardwareEventLogger() {
  useBluetoothEvent('button_press', (event) => console.log(event));
  useBluetoothEvent('touch_event', (event) => console.log(event));
  useBluetoothEvent('photo_response', (event) => console.log(event));
  useBluetoothEvent('photo_status', (event) => console.log(event.status, event.resolvedConfig));
  useBluetoothEvent('stream_status', (event) => console.log(event.resolvedConfig?.video?.fps));
  useBluetoothEvent('ota_status', (event) => console.log(event.overall_percent));
  useBluetoothEvent('speaking_status', (event) => console.log(event.speaking));
  useBluetoothEvent('mic_pcm', (event) => {
    console.log(event.sampleRate, event.bitsPerSample, event.channels, event.encoding);
    console.log(event.pcm);
  });

  return null;
}
For non-React modules, BluetoothSdk.addListener(...) is the low-level subscription API. Keep the returned subscription and call remove() when the listener is no longer needed. The React Native event surface is typed through BluetoothSdkEventMap. These are the public event names accepted by useBluetoothEvent() and BluetoothSdk.addListener():
Event namePayload typeWhen it fires
logLogEventSDK diagnostic log line.
device_discoveredDeviceA supported glasses device is discovered during scan.
default_device_changed{device?: Device}The SDK default device changes.
glasses_not_readyGlassesNotReadyEventA command needs ready glasses but the connected device is not ready.
button_pressButtonPressEventGlasses button press.
touch_eventTouchEventGlasses touch or swipe gesture.
head_upHeadUpEventHead-up state changes.
voice_activity_detection_statusVoiceActivityDetectionStatusEventGlasses-side Voice Activity Detection is enabled or disabled.
speaking_statusSpeakingStatusEventGlasses-side Voice Activity Detection reports speaking or not speaking.
battery_statusBatteryStatusEventBattery update from glasses.
local_transcriptionLocalTranscriptionEventSDK local transcription text update.
wifi_status_changeWifiStatusChangeEventGlasses Wi-Fi connection state changes.
hotspot_status_changeHotspotStatusChangeEventGlasses hotspot state changes.
hotspot_errorHotspotErrorEventHotspot operation fails.
photo_responsePhotoResponseEventPhoto request succeeds or fails.
photo_statusPhotoStatusEventPhoto capture progress changes. May include resolvedConfig, requestedCaptureConfig, meteredPreview, or captureMetadata depending on status.
gallery_statusGalleryStatusEventGallery content/camera-busy status changes.
compatible_glasses_search_stopCompatibleGlassesSearchStopEventCompatible-glasses search stops for a model.
swipe_volume_statusSwipeVolumeStatusEventSwipe-volume setting changes.
switch_statusSwitchStatusEventGlasses switch status changes.
rgb_led_control_responseRgbLedControlResponseEventRGB LED command succeeds or fails.
pair_failurePairFailureEventBluetooth pairing fails.
audio_pairing_neededAudioPairingNeededEventThe phone needs Bluetooth audio pairing for the device.
audio_connectedAudioConnectedEventBluetooth audio connects.
audio_disconnectedAudioDisconnectedEventBluetooth audio disconnects.
mic_pcmMicPcmEventPCM microphone frame arrives.
mic_lc3MicLc3EventLC3 microphone frame arrives.
stream_statusStreamStatusEventCamera stream lifecycle, reconnect, or error state changes. May include resolvedConfig with effective stream settings: encoded output size in video.width / video.height, native camera capture size in video.captureWidth / video.captureHeight, video bitrate and fps, plus audio bitrate, sample rate, echo cancellation, and noise suppression.
ota_update_availableOtaUpdateAvailableEventMentra Live reports an available OTA package.
ota_start_ackOtaStartAckEventMentra Live acknowledges startOtaUpdate().
ota_statusOtaStatusEventOTA step, phase, status, progress, or error changes.
For example, useBluetoothEvent('photo_response', ...) receives a PhotoResponseEvent, while useBluetoothEvent('mic_pcm', ...) receives a MicPcmEvent. MicPcmEvent includes sampleRate, bitsPerSample, channels, encoding, and voiceActivityDetectionEnabled; MicLc3Event includes sampleRate, channels, encoding, frameDurationMs, frameSizeBytes, bitrate, packetizedFromGlasses, and voiceActivityDetectionEnabled. speaking_status is separate from microphone audio frames so apps can use continuous audio while still reacting to speech activity. Public React Native event payload fields usually use camelCase. OTA events intentionally mirror the glasses firmware field names, such as overall_percent and version_name. For example, touch events expose deviceModel and gestureName, successful photo responses expose uploadUrl, hotspot errors expose errorMessage, and gallery status exposes hasContent and cameraBusy.

Photo Status Metadata

PhotoStatusEvent reports progress through capture and transfer. Capture metadata is attached to the stage where the glasses know that data:
StatusOptional fieldDescription
configuringresolvedConfigEffective JPEG dimensions, quality, requested size, source (sdk or button), transfer method, compression, and manual exposure fields when present.
capturingrequestedCaptureConfigCamera2 still request values submitted to the HAL, such as exposure time, ISO, frame duration, AE mode, AE lock, exposure compensation, target FPS range, AF mode, and ZSL.
capturingmeteredPreviewLatest preview auto-exposure estimate before the still capture, including exposure time, ISO, and a light proxy when available.
capturedcaptureMetadataActual still capture result returned by the HAL, including applied exposure time, ISO, frame duration, AE state/name, noise reduction mode, edge mode, sensor timestamp, and MFNR hint when available.
Transport statuses such as uploading, compressing, ble_fallback_compression, ready_for_transfer, and transferring describe upload or BLE progress only and do not carry capture metadata. ble_fallback_compression means the direct Wi-Fi/webhook upload failed and the glasses are compressing the already-captured photo for Bluetooth fallback delivery. Apps should read actual capture values from event.captureMetadata on the captured status, not from upload statuses. Local action-button photos emitted by the glasses use the same photo_status shape when the phone SDK is connected. Those local captures set resolvedConfig.source to button and resolvedConfig.transferMethod to local. Android and iOS expose typed callbacks/delegate methods instead of the React Native string event API. Android uses MentraBluetoothSdkListener methods such as onStateChanged, onGlassesChanged, onSdkStateChanged, onScanChanged, onDeviceDiscovered, onButtonPress, onSpeakingStatus, onPhotoResponse, onPhotoStatus, onMicPcm, onStreamStatus, and onOtaStatus. iOS uses MentraBluetoothSDKDelegate methods such as mentraBluetoothSDK(_:didUpdate:), mentraBluetoothSDK(_:didUpdateGlasses:), mentraBluetoothSDK(_:didUpdateSdkState:), mentraBluetoothSDK(_:didUpdateScan:), mentraBluetoothSDK(_:didDiscover:), mentraBluetoothSDK(_:didReceive:), mentraBluetoothSDK(_:didReceiveMicPcm:), and mentraBluetoothSDK(_:didReceiveMicLc3:); OTA arrives through didReceive as .otaUpdateAvailable, .otaStartAck, or .otaStatus. Microphone audio callbacks use MicPcmEvent and MicLc3Event objects with the same metadata as React Native.
Event areaExamples
InputButton press, touch, swipe, head-up
Device stateBattery, case, Wi-Fi, hotspot, connection, RSSI
CameraPhoto request result, gallery state, camera settings
StreamingStream initializing, active, stopped, error
OTAUpdate available, start acknowledged, step/progress status
AudioMicrophone PCM, LC3, local transcription, audio route state
DiagnosticsSDK log events

Version Fields

Call requestVersionInfo() after connection when your app wants the glasses to refresh version metadata. Updated values arrive through the normal glasses-status callback and are also available in the next status snapshot.
FieldMeaning
firmwareVersionGeneric glasses firmware version when the connected model reports one.
deviceFirmwareVersionDevice firmware version for models that report device info as a structured payload.
leftFirmwareVersion / rightFirmwareVersionPer-side firmware versions for glasses that report left/right firmware separately.
besFirmwareVersionMentra Live BES firmware version.
mtkFirmwareVersionMentra Live MTK/system OTA firmware version.
appVersionGlasses-side companion app version. On Mentra Live this is the ASG client APK version, not firmware.
androidVersionAndroid OS version on Android-based glasses. This is not firmware.
Different glasses models expose different version fields, so apps should prefer the generic firmware field when present, then fall back to model-specific firmware fields. Keep app and OS versions visibly labeled as app/OS versions.