Bodygram
Playground

Scanflow Playground

Embed the Bodygram camera scanner, configure scan options, and handle captured photos.

Overview

Scanflow is the built-in scanning UI provided by the Headless SDK. When invoked, it embeds a guided camera interface into your page that walks the user through capturing two photos — a front-facing shot and a side-facing shot — which Bodygram uses to estimate body measurements.

The full scanflow consists of two screens:

  • Introduction — an optional screen shown before the camera opens. Use it to welcome users, set expectations, or explain how to position for an accurate scan.
  • Scan — the camera interface where the user positions themselves and captures each photo.

Both screens are configurable. You can skip the introduction, swap modal styles, or drive the flow programmatically to match your product's UX.


Implementation

Call sdk.scan() to launch the scanflow. It returns a promise that resolves with the captured front and side photos once the user completes the scan.

const { front, side } = await sdk.scan({
  silhouette: 'female',
  welcomeModal: 'how-to-scan',
  screensToInclude: ['how-to-scan', 'scan'],
  isMirrored: true,
  hasHeader: true,
  hasActionsArea: true,
  isDebuggerEnabled: false,
  camera: { facingMode: 'user' },
});

Configuration

All fields are optional.

OptionTypeDescription
cameraMediaTrackConstraintsConstraints passed to getUserMedia. Use to select front/rear camera, set resolution, etc. To request the back camera, pass { facingMode: 'environment' } — note that availability depends on the browser and device.
silhouette"male" | "female"Overlay silhouette shown in the scanner to guide user positioning.
isDebuggerEnabledbooleanEnables the on-screen debug panel. Useful during development. Defaults to false.
screensToIncludeScreenID[]List of screens to include in the flow. Valid values: "scan", "how-to-scan", "all".
welcomeModal'tap-to-start' | 'how-to-scan' | falseControls the intro modal shown before the scanner opens. 'how-to-scan' shows positioning instructions before the camera opens. false skips the modal entirely. 'tap-to-start' shows a minimal tap prompt — use this on iOS when screensToInclude is set to ["scan"] only: without a prior screen, no user gesture has been registered, and iOS will block audio playback. This is not an issue on Android. Defaults to 'how-to-scan'.
isMirroredbooleanMirrors the camera preview horizontally. Defaults to true for front-facing cameras.
hasHeaderbooleanShows or hides the header bar on the scan screen only. Defaults to false.
hasActionsAreabooleanShows or hides the bottom actions area on the scan screen only. Defaults to false.
audioobjectCustom voice guidance — play your own clips around scan steps, or replace / silence built-in clips. See Custom voice guidance.
canSkipTutorialOnGoodPosebooleanWhen true, a user already in a good pose skips the tutorial (and any custom clips attached to it). Defaults to true.

Camera width and height constraints depend on the device's camera capabilities. Not all devices support the same resolution ranges.

hasHeader and hasActionsArea apply to the scan screen only. The introduction screen (e.g. how-to-scan) always renders its own header and actions area. Configurable introduction screen layout is planned for a future release.


Custom voice guidance

Scanflow narrates each step of the scan. Pass audio to change what users hear:

  • audio.steps — play extra clips before or after a step's own clip.
  • audio.tracks — replace a built-in clip with your own URL, or set it to null to silence it.
const { front, side } = await sdk.scan({
  canSkipTutorialOnGoodPose: false,
  audio: {
    steps: {
      FrontTutorial1: { before: ['https://cdn.example.com/audio/{lang}/welcome.mp3'] },
      SideTutorial: { after: ['https://cdn.example.com/audio/{lang}/look-down.mp3'] },
    },
    tracks: {
      FrontScan_VoiceGuidance_FrontFeedbackOffCenter: null,
    },
  },
});

{lang} in a URL is replaced with the SDK locale, so one URL can serve every language.

Trying it in the playground

In Try it, open the Voice guidance section:

  1. Click load example to fill in a working setup: a Bodygram clip played after SideTutorial, and the off-center feedback clip silenced.
  2. Use + add step clip to pick a step, choose before or after, and paste a clip URL. Add several rows for the same step to play clips in sequence.
  3. Use + add track override to pick a built-in track and either replace it with a URL or silence it.
  4. Turn off canSkipTutorialOnGoodPose if you attached clips to FrontTutorial1, FrontTutorial2, or SideTutorial. Otherwise a user already in a good pose skips the tutorial and never hears them.
  5. Click Launch Scanflow. The code panel shows the matching audio config to copy into your app.

Clips must be MP3 files — other audio formats are not supported. Clip URLs must be absolute https URLs, and the host must send an Access-Control-Allow-Origin header — clips are fetched and decoded in the browser. If a clip fails to load, the default Bodygram clip plays instead.

Step clips are blocking: the scan waits for each clip to finish, so every clip adds its length to the scan.

See Custom voice guidance in the API reference for the full list of steps and tracks.


Error handling

sdk.scan() returns a promise that can reject in two cases:

CodeWhen
SCAN_CLOSED_BY_USERThe user closed the scanner before completing the scan.
SCAN_FAILEDThe scan could not be completed due to an unexpected error.
try {
  const { front, side } = await sdk.scan(config);
} catch (err) {
  if (err.code === 'SCAN_CLOSED_BY_USER') {
    // user dismissed the scanner
  } else if (err.code === 'SCAN_FAILED') {
    // something went wrong during the scan
  }
}

Try it

Configure the options below and launch the scanner with your client key.

Interactive Demo

Scanner

Camera

ideal
exact
min
max

Values are pixels. Focus a field to see what it does.

ideal
exact
min
max

Values are pixels. Focus a field to see what it does.

Display

Voice guidance

CODE
const sdk = new BodygramSDK({
  clientKey: 'YOUR_CLIENT_KEY',
  locale: 'en',
});

const { front, side } = await sdk.scan({
  welcomeModal: 'how-to-scan',
  screensToInclude: ['scan', 'how-to-scan'],
  camera: {
    facingMode: 'user',
  },
  isMirrored: true,
  hasHeader: false,
  hasActionsArea: false,
  isDebuggerEnabled: false,
});

API reference

Detailed signatures, parameters, and response shapes for everything used on this page live in the Headless SDK API reference.

Methods

  • scan(config?) — open the scanner UI and resolve with the captured front and side photos as base64 strings.
  • Custom voice guidance — every audio.steps step and audio.tracks track name.

Initialization

On this page