iFrame Integration
Embed FaceGuard directly using an iframe for full control over sizing and layout.
Communication Method
The iframe integration uses postMessage for all communication. Events are sent via window.postMessage and received through the message event listener.
Mobile (Fullscreen)
HTML
<div
id="faceguard-container"
style="position: fixed; inset: 0; z-index: 9999; background: #0D141A;"
>
<iframe
src="https://faceguard.surt.com/intro?token=YOUR_PORTAL_TOKEN"
allow="camera"
style="width: 100%; height: 100%; border: none;"
></iframe>
</div>
Desktop (Phone-shaped Modal)
HTML
<div
id="faceguard-backdrop"
style="
position: fixed; inset: 0; z-index: 9999;
background: rgba(0, 0, 0, 0.6);
display: flex; align-items: center; justify-content: center;
"
>
<div style="
width: 420px; height: 760px;
border-radius: 24px; overflow: hidden;
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
">
<iframe
src="https://faceguard.surt.com/intro?token=YOUR_PORTAL_TOKEN"
allow="camera"
style="width: 100%; height: 100%; border: none;"
></iframe>
</div>
</div>
Desktop (QR Code)
For desktop users, use the /qrcode route to show a QR code that opens the verification on their phone:
HTML
<iframe
src="https://faceguard.surt.com/qrcode?token=YOUR_PORTAL_TOKEN"
allow="camera"
style="width: 420px; height: 760px; border: none; border-radius: 24px;"
></iframe>
Required Attributes
| Attribute | Purpose |
|---|---|
allow="camera" | Grants camera access inside the iframe |
Camera required
The allow="camera" attribute is mandatory. Without it, the browser blocks camera access and FaceGuard emits { action: 'close', reason: 'error', error: 'camera_insecure_context' }.
Event Handling
JavaScript
window.addEventListener('message', (event) => {
// Verify origin in production
if (event.origin !== 'https://faceguard.surt.com') return;
const data = event.data;
if (data.type === 'surt:ready') {
console.log('FaceGuard loaded');
return;
}
if (data.action === 'close') {
switch (data.reason) {
case 'approved':
console.log('Verified', data.confidence);
break;
case 'rejected':
console.log('Failed', data.confidence);
break;
case 'canceled':
console.log('User canceled');
break;
case 'bypass_active':
console.log('Bypass active until', data.bypass_expires_at);
break;
case 'no_base_photo':
console.log('No base photo on file');
break;
case 'error':
// `data.error` is a typed code — see Camera Error Codes in the reference
switch (data.error) {
case 'camera_permission_denied':
showToast('Please allow camera access in your browser settings, then try again.');
break;
case 'camera_unavailable':
showToast('No camera detected on this device.');
break;
case 'camera_in_use':
showToast('Your camera is in use by another app or tab.');
break;
case 'camera_insecure_context':
// Likely a misconfigured embed — log to your monitoring
console.error('FaceGuard: camera blocked, check HTTPS and allow="camera".');
break;
default:
console.log('FaceGuard error:', data.error);
}
break;
}
// Remove iframe
document.getElementById('faceguard-container')?.remove();
}
});
Events Reference
| Event | Payload | Description |
|---|---|---|
| Ready | { type: 'surt:ready' } | FaceGuard is loaded and ready |
| Approved | { action: 'close', reason: 'approved', confidence: number } | Face verified (0-100 score) |
| Rejected | { action: 'close', reason: 'rejected', confidence: number } | Face did not match (0-100 score) |
| Canceled | { action: 'close', reason: 'canceled' } | User closed FaceGuard |
| Bypass | { action: 'close', reason: 'bypass_active', bypass_expires_at: string } | Customer has active bypass |
| No Base Photo | { action: 'close', reason: 'no_base_photo' } | No enrolled photo to compare against |
| Error | { action: 'close', reason: 'error', error: string } | Something went wrong. The error value is a typed code — see Camera Error Codes. |
URL Parameters
| Parameter | Description |
|---|---|
token | Portal JWT (required) |
lang | Language override: en, es, pt, de (optional) |
Sizing
FaceGuard is designed at 375x812px and scales automatically.
- Mobile: full viewport (
100vw x 100vh) - Desktop: recommended 420x760px with 24px border-radius
- Minimum: 320px width
Dark Background
Set background: #0D141A on the iframe container to prevent a white flash while loading.
Security Headers
If your site uses Content Security Policy or Permissions-Policy headers:
frame-src https://faceguard.surt.com;
Permissions-Policy: camera=(self "https://faceguard.surt.com")