Use session.camera.takePhoto() to capture a photo from the user’s smart glasses. The method returns a promise that resolves with the photo data.

Quick Start

import { MiniAppServer, type MentraSession } from "@mentra/sdk";

const app = new MiniAppServer();

app.onSession((session) => {
  session.transcription.on((data) => {
    if (!data.isFinal) return;

    if (data.text.toLowerCase().includes("take photo")) {
      session.camera.takePhoto().then((photo) => {
        session.logger.info(`Photo captured: ${photo.url}`);
        session.logger.info(`Resolution: ${photo.width}x${photo.height}`);
      });
    }
  });
});

app.start();

Permissions

Your app needs the camera permission to take photos. Add it in the Developer Console when creating or editing your app. Check permission at runtime:
if (session.camera.hasPermission) {
  const photo = await session.camera.takePhoto();
  session.logger.info(`Captured: ${photo.url}`);
} else {
  session.logger.warn("Camera permission not granted");
}

Options

Pass an options object to control the capture:
const photo = await session.camera.takePhoto({
  size: "large",
  compression: "high",
  saveToGallery: true,
  sound: true,
  timeout: 10000,
});
OptionTypeDefaultDescription
size"small" | "medium" | "large" | "full""medium"Photo resolution
compressionstringundefinedCompression level
saveToGallerybooleanfalseSave the photo to the user’s gallery
soundbooleantruePlay a shutter sound on capture
timeoutnumber5000Timeout in milliseconds

Return Value

takePhoto() returns a Promise<PhotoData> with the following fields:
FieldTypeDescription
urlstringURL to the captured photo
widthnumberPhoto width in pixels
heightnumberPhoto height in pixels
timestampnumberUnix timestamp of the capture
savedToGallerybooleanWhether the photo was saved to the gallery

Photo Sizes

The resolution depends on the requested size and connection type.
SizeWiFi ResolutionBLE Resolution
small640x480400x300
medium1280x960640x480
large1920x1440800x600
full3264x24481024x768
All photos maintain a 4:3 aspect ratio. Over BLE, photos are compressed more aggressively to fit Bluetooth bandwidth constraints.

Common Patterns

Take a photo and upload it

app.onSession((session) => {
  session.transcription.on(async (data) => {
    if (!data.isFinal) return;

    if (data.text.toLowerCase().includes("capture")) {
      try {
        const photo = await session.camera.takePhoto({ size: "large" });
        session.logger.info(`Uploading photo: ${photo.url}`);

        await fetch("https://your-api.com/upload", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ imageUrl: photo.url }),
        });

        session.speaker.speak("Photo uploaded");
      } catch (error) {
        session.logger.error("Photo capture failed", error);
      }
    }
  });
});

Take multiple photos with a delay

async function captureSequence(session: MentraSession, count: number) {
  const photos = [];
  for (let index = 0; index < count; index++) {
    const photo = await session.camera.takePhoto({ size: "small" });
    photos.push(photo);
    session.logger.info(`Captured ${index + 1}/${count}`);
    await new Promise((resolve) => setTimeout(resolve, 1000));
  }
  return photos;
}
const photo = await session.camera.takePhoto({
  saveToGallery: true,
  size: "full",
});

session.logger.info(`Saved to gallery: ${photo.savedToGallery}`);

Migrating from v2

Three changes to be aware of:
  • requestPhoto() is now takePhoto(). The method name changed, but the usage pattern is the same.
  • customWebhookUrl and authToken options are removed. Photos are returned directly from the promise.
  • onPhotoTaken() is deprecated. Use the promise returned by takePhoto() instead.
// v2
const photo = await session.camera.requestPhoto({ size: "large" });

// v3
const photo = await session.camera.takePhoto({ size: "large" });
See the Migration Guide for the full list of changes.