Integração iFrame
Integre o FaceGuard diretamente usando um iframe para controlo total sobre dimensionamento e layout.
A integração com iframe usa postMessage para toda a comunicação. Os eventos são enviados via window.postMessage e recebidos através do listener do evento message.
Móvel (ecrã completo)
<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 (modal em forma de telemóvel)
<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 (código QR)
Para utilizadores de desktop, use a rota /qrcode para mostrar um código QR que abre a verificação no telemóvel:
<iframe
src="https://faceguard.surt.com/qrcode?token=YOUR_PORTAL_TOKEN"
allow="camera"
style="width: 420px; height: 760px; border: none; border-radius: 24px;"
></iframe>
Atributos obrigatórios
| Atributo | Finalidade |
|---|---|
allow="camera" | Concede acesso à câmara dentro do iframe |
O atributo allow="camera" é obrigatório. Sem ele, o browser bloqueia o acesso à câmara e o FaceGuard emite { action: 'close', reason: 'error', error: 'camera_insecure_context' }.
Gestão de eventos
window.addEventListener('message', (event) => {
// Verifique a origem em produção
if (event.origin !== 'https://faceguard.surt.com') return;
const data = event.data;
if (data.type === 'surt:ready') {
console.log('FaceGuard carregado');
return;
}
if (data.action === 'close') {
switch (data.reason) {
case 'approved':
console.log('Verificado', data.confidence);
break;
case 'rejected':
console.log('Falhado', data.confidence);
break;
case 'canceled':
console.log('Utilizador cancelou');
break;
case 'bypass_active':
console.log('Bypass ativo até', data.bypass_expires_at);
break;
case 'no_base_photo':
console.log('Sem foto base registada');
break;
case 'error':
// `data.error` é um código tipado — ver Códigos de erro de câmara na referência
switch (data.error) {
case 'camera_permission_denied':
showToast('Permita o acesso à câmara nas definições do browser e tente novamente.');
break;
case 'camera_unavailable':
showToast('Nenhuma câmara detetada neste dispositivo.');
break;
case 'camera_in_use':
showToast('A sua câmara está a ser usada por outra app ou separador.');
break;
case 'camera_insecure_context':
// Embed mal configurado — registar na monitorização
console.error('FaceGuard: câmara bloqueada, verifique HTTPS e allow="camera".');
break;
default:
console.log('Erro do FaceGuard:', data.error);
}
break;
}
// Remover iframe
document.getElementById('faceguard-container')?.remove();
}
});
Referência de eventos
| Evento | Payload | Descrição |
|---|---|---|
| Pronto | { type: 'surt:ready' } | FaceGuard está carregado e pronto |
| Aprovado | { action: 'close', reason: 'approved', confidence: number } | Rosto verificado (pontuação 0-100) |
| Rejeitado | { action: 'close', reason: 'rejected', confidence: number } | Rosto não correspondeu (pontuação 0-100) |
| Cancelado | { action: 'close', reason: 'canceled' } | Utilizador fechou o FaceGuard |
| Bypass | { action: 'close', reason: 'bypass_active', bypass_expires_at: string } | Cliente tem bypass ativo |
| Sem foto base | { action: 'close', reason: 'no_base_photo' } | Sem foto registada para comparar |
| Erro | { action: 'close', reason: 'error', error: string } | Algo correu mal. O valor de error é um código tipado — ver Códigos de erro de câmara. |
Parâmetros de URL
| Parâmetro | Descrição |
|---|---|
token | JWT de portal (obrigatório) |
lang | Idioma: en, es, pt, de (opcional) |
Dimensionamento
O FaceGuard foi concebido para 375x812px e escala automaticamente.
- Móvel: viewport completo (
100vw x 100vh) - Desktop: 420x760px recomendado com border-radius de 24px
- Mínimo: 320px de largura
Defina background: #0D141A no contentor do iframe para evitar um flash branco durante o carregamento.
Cabeçalhos de segurança
Se o seu site usar cabeçalhos Content Security Policy ou Permissions-Policy:
frame-src https://faceguard.surt.com;
Permissions-Policy: camera=(self "https://faceguard.surt.com")