Face Scan Embed API
Self-hosted integration documentation for the Face Scan experience
The Face Scan Embed API enables partners to deploy a Next.js application that collects user intake details, creates patient records, and loads the Face Scan experience within an iframe.
This documentation covers the complete integration flow, including authentication, environment setup, data requirements, and runtime behavior.
Integration Method
iframe only - All integrations must use the iframe embed method with camera permissions enabled.
Authentication
Authentication is handled through a validate endpoint that returns a bearer token. This token must be included in all Create Patient API requests.
Required Credentials
Provided by Face Scan per partner and environment
funnelIDPartner attribution ID (e.g., partner-acme-prod)
AWS_VALIDATE_URLEndpoint URL for token retrieval
AWS_USERNAME / AWS_PASSWORDCredentials for validate authentication
Scan base URLBase URL for scan iframe (e.g., https://vitals.scanyourface.co)
Environment Variables
Configure these environment variables in your hosting platform. Without them, createPatient or scan loading will fail.
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_SCAN_BASE_URL | Yes | Base scan page URL |
AWS_VALIDATE_URL | Yes | Validate endpoint URL |
AWS_USERNAME | Yes | Validate username |
AWS_PASSWORD | Yes | Validate password |
AWS_CREATE_PATIENT_URL | Yes | Create Patient API base URL |
AWS_CREATE_PATIENT_DATA_TYPE | Optional | Defaults to non-sensitive |
Website Integration
Embed the deployed application in your website using an iframe with camera permissions enabled.
Implementation
<iframe
src="https://YOUR-EMBED-DOMAIN.com?funnelID=YOUR_FUNNEL_ID"
allow="camera; microphone"
style="width:100%; min-height:85vh; border:0;"
></iframe>⚠️ Important Requirements
- Your website must be served over HTTPS
- The iframe must include allow="camera; microphone"
- If content appears clipped, increase min-height or use full-height container
Required Intake Fields
The embed flow collects these inputs before proceeding to the scan. All fields are sent to createPatient.
Demographics
- • biologicalSex
- • age
- • height (cm)
- • weight
Health Data
- • hypertension (boolean)
Location
- • city
- • state
- • zip
Contact & Consent
- • firstName
- • lastName
- • phone
- • tcpaConsent
Create Patient API
Your embed application calls this endpoint via /api/create-patient to register a patient and obtain confirmation.
Request Payload
{
"patientUUID": "550e8400-e29b-41d4-a716-446655440000",
"funnelID": "partner-acme-prod",
"assessmentType": "FaceScan",
"biologicalSex": "male",
"age": 35,
"height": 175,
"weight": 70,
"hypertension": false,
"city": "San Francisco",
"state": "CA",
"zip": "94102",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"tcpaConsent": true
}Runtime Flow
- User completes all intake screens
- System generates unique
patientUUID - Call
/api/create-patientwith intake data - Endpoint calls validate to obtain bearer token
- Endpoint calls Create Patient API with token and payload
- Build scan URL with PatientUUID, funnelID, and embedData
- Load scan iframe
Embed Data
embedData is a base64url-encoded JSON string passed to the scan page containing required demographics for the Face Scan SDK.
Required Fields
sex0 = female, 1 = male
ageNumber value
heightValue in centimeters
weightNumber value
bp_modeTernary value (implementation-specific)
bp_grouphypertension / normal
facing_modeuser or environment
emailUser email address
Encoding Example
function toBase64Url(obj) {
const json = JSON.stringify(obj);
const b64 = btoa(unescape(encodeURIComponent(json)));
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
// Example usage
const embedData = toBase64Url({
sex: 1,
age: 35,
height: 175,
weight: 70,
bp_mode: 0,
bp_group: "normal",
facing_mode: "user",
email: "john.doe@example.com"
});
const scanUrl = `${scanBaseUrl}/scan.html?PatientUUID=${uuid}&funnelID=${funnelID}&embedData=${embedData}`;Decoding Example
function fromBase64Url(str) {
let b64 = str.replace(/-/g, '+').replace(/_/g, '/');
while (b64.length % 4) b64 += '=';
const json = decodeURIComponent(escape(atob(b64)));
return JSON.parse(json);
}PostMessage Events
The scan iframe communicates with the embed application via postMessage events. Listen for these events to handle scan lifecycle.
HIQOR_SCAN_COMPLETEFired when scan completes successfully. Scan page typically redirects to results view inside iframe.
HIQOR_CAMERA_ERRORCamera initialization failed. Show retry overlay - retry should reload scan iframe.
{
"type": "HIQOR_CAMERA_ERROR",
"message": "Camera access denied"
}HIQOR_START_MEASURING_FAILEDMeasurement process failed to start. Show retry overlay - retry should reload scan iframe.
HIQOR_IFRAME_HEIGHTResize hint to adjust iframe height and avoid clipping (if implemented).
Implementation Example
window.addEventListener('message', (event) => {
const { type, message } = event.data;
switch (type) {
case 'HIQOR_SCAN_COMPLETE':
console.log('Scan completed successfully');
// Handle completion
break;
case 'HIQOR_CAMERA_ERROR':
console.error('Camera error:', message);
// Show retry UI
break;
case 'HIQOR_START_MEASURING_FAILED':
console.error('Measurement failed:', message);
// Show retry UI
break;
case 'HIQOR_IFRAME_HEIGHT':
// Adjust iframe height if needed
break;
}
});Refresh Methods
Different refresh strategies achieve different outcomes. Choose the correct method based on your use case.
Retry During Scan (Recommended)
Use for camera or measurement failures. Reloads scan iframe with same PatientUUID.
// Reload iframe src to retry scan
iframe.src = iframe.src;Refresh Results View
Refreshes the results displayed inside the scan iframe. Add cache-busting timestamp if needed.
<iframe
src="https://YOUR-EMBED-DOMAIN.com?funnelID=YOUR_FUNNEL_ID&ts=1700000000000"
allow="camera; microphone"
style="width:100%; min-height:85vh; border:0;"
></iframe>Start New Scan Session
Refresh the full embed app to restart intake flow with new PatientUUID.
// Refresh parent embed to start completely new scan
window.location.reload();Troubleshooting
Common issues and their solutions.
Camera not working
Cause: Missing HTTPS or camera permissions
Solution: Ensure website uses HTTPS and iframe includes allow="camera; microphone"
createPatient failing
Cause: Invalid credentials or missing environment variables
Solution: Verify AWS_VALIDATE_URL, AWS_USERNAME, AWS_PASSWORD, and AWS_CREATE_PATIENT_URL are correctly set
Blank scan iframe
Cause: Incorrect scan base URL
Solution: Confirm NEXT_PUBLIC_SCAN_BASE_URL is correct and /scan.html endpoint is reachable
Missing demographics errors
Cause: embedData not included or malformed
Solution: Ensure embedData is properly base64url-encoded and includes all required fields
Need Support?
Provide these details when requesting assistance:
- Your embed deployment URL and iframe src URL (including funnelID)
- Timestamp of the test and browser/device used
- Screenshots of errors and console output
- HTTP status and error message from /api/create-patient
Go-Live Checklist
Complete this checklist before deploying to production.
- Confirm funnelID is present and correct in iframe src URL
- Verify all environment variables are set and deployment has been redeployed
- Test scan on desktop Chrome and at least one mobile browser
- Verify createPatient succeeds (no 401/403 from validate; no 5xx from createPatient)
- Verify camera permission prompt appears and scan completes
- Verify "Try again" works for camera errors