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.
| Option | Type | Description |
|---|---|---|
camera | MediaTrackConstraints | Constraints 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. |
isDebuggerEnabled | boolean | Enables the on-screen debug panel. Useful during development. Defaults to false. |
screensToInclude | ScreenID[] | List of screens to include in the flow. Valid values: "scan", "how-to-scan", "all". |
welcomeModal | 'tap-to-start' | 'how-to-scan' | false | Controls 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'. |
isMirrored | boolean | Mirrors the camera preview horizontally. Defaults to true for front-facing cameras. |
hasHeader | boolean | Shows or hides the header bar on the scan screen only. Defaults to false. |
hasActionsArea | boolean | Shows or hides the bottom actions area on the scan screen only. Defaults to false. |
audio | object | Custom voice guidance — play your own clips around scan steps, or replace / silence built-in clips. See Custom voice guidance. |
canSkipTutorialOnGoodPose | boolean | When 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 clipsbeforeoraftera step's own clip.audio.tracks— replace a built-in clip with your own URL, or set it tonullto 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:
- Click load example to fill in a working setup: a Bodygram clip played after
SideTutorial, and the off-center feedback clip silenced. - Use + add step clip to pick a step, choose
beforeorafter, and paste a clip URL. Add several rows for the same step to play clips in sequence. - Use + add track override to pick a built-in track and either replace it with a URL or silence it.
- Turn off canSkipTutorialOnGoodPose if you attached clips to
FrontTutorial1,FrontTutorial2, orSideTutorial. Otherwise a user already in a good pose skips the tutorial and never hears them. - Click Launch Scanflow. The code panel shows the matching
audioconfig 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:
| Code | When |
|---|---|
SCAN_CLOSED_BY_USER | The user closed the scanner before completing the scan. |
SCAN_FAILED | The 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
Values are pixels. Focus a field to see what it does.
Values are pixels. Focus a field to see what it does.
Display
Voice guidance
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.stepsstep andaudio.trackstrack name.
Initialization
new BodygramSDK({ clientKey, locale, ... })— construct the SDK before callingscan().
