Options
Tout ce que Handler.load() accepte : la stratégie de mesure, la fonction de rappel d’événements, la palette de onze couleurs, les écrans et les textes.
Une nouvelle intégration devrait utiliser Saphere Scan v2. Ce qui suit documente l’objet d’options de la v1.
Vos options sont validées, puis fusionnées par-dessus les valeurs par défaut — et par-dessus toute personnalisation appliquée par ?customizationId=. Les clés de premier niveau inconnues sont refusées plutôt qu’ignorées.
Premier niveau
| Clé | Type | Défaut | Remarques |
|---|---|---|---|
createMeasure | objet | — | Requis. Comment une mesure est obtenue. |
onEvent | fonction | — | Appelée à chaque événement. |
allowLeave | booléen | false | Affiche une commande permettant à l’utilisateur de quitter le widget. |
allowSkip | booléen | false | Permet à l’utilisateur de passer les écrans d’accueil. |
lang | chaîne | langue du navigateur, sinon "en" | L’une des dix langues prises en charge. |
useShadow | booléen | true | Monte dans un shadow root. |
colors | objet | voir plus bas | Onze couleurs hexadécimales. |
texts | objet | intégrés | Réécriture des chaînes, par langue. |
pages | objet | voir plus bas | Quels écrans apparaissent, et comment. |
desiredVariables | string[] | — | Réduit ce qui est calculé. |
tags | string[] | — | Conservés avec la mesure. |
`useShadow: false` laisse votre CSS entrer
Par défaut, le widget est monté dans un shadow root, ce qui empêche votre feuille de style de l’affecter et la sienne de vous affecter. Désactiver cela est parfois nécessaire dans les coquilles hybrides ; attendez-vous alors à ce que votre CSS global atteigne les entrailles du widget.createMeasure
Le widget a besoin d’une mesure à laquelle rattacher la capture. Il existe deux stratégies, et elles diffèrent par qui fait l’appel.
delegate — le widget appelle votre point d’accès
createMeasure: {
strategy: "delegate",
url: "/api/saphere-measure",
headers: { "X-Session": sessionId } // facultatif
}
Le widget émet POST <url> avec un corps JSON portant userData, desiredVariables et tags, et attend { "id": "<measureId>" } en retour.
Votre point d’accès authentifie votre utilisateur, appelle POST /measures sur l’API Saphere avec votre clé, et relaie l’identifiant.
handle — votre code fait l’appel
createMeasure: {
strategy: "handle",
fetch: async ({ userData, desiredVariables }) => {
const response = await fetch("/api/saphere-measure", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userData, desiredVariables })
})
return await response.json() // doit être { id: "…" }
}
}
`fetch` doit résoudre vers un objet portant un `id`
Rendre l’identifiant sous la forme d’une chaîne nue lève Cannot get measureId!. Le contrat est { id: string } — un objet.
Cela vaut d’être vérifié en premier quand une intégration v1 échoue dès le départ : certains exemples publiés rendaient json["token"], qui est une chaîne, et ne le satisfait pas.
Si le point d’accès répond avec un statut hors 2xx, le widget lève Cannot create measure!.
onEvent
onEvent: async event => {
console.log(event.type, event)
}
Appelée pour chaque événement ci-dessous. La valeur rendue est significative : rendre littéralement false annule la transition que l’événement annonce. Tout le reste — y compris undefined, et y compris une exception levée, qui est journalisée et avalée — l’autorise.
Le gestionnaire est attendu.
Un gestionnaire lent ralentit le widget
Parce que la valeur rendue peut opposer un veto à une transition, la v1 attend votre gestionnaire avant de poursuivre. Un gestionnaire qui fait un appel réseau à chaque événement retarde le parcours utilisateur d’autant.
C’est le comportement que la v2 a délibérément abandonné : là, onEvent n’est jamais attendu, et le veto a migré vers une API hooks distincte, bornée par un délai.
L’union des événements
type | Charge utile | Quand |
|---|---|---|
video-stream-loading | { status: "start" } | La caméra est demandée |
video-stream-loading | { status: "ready" } | Le flux est ouvert |
video-stream-loading | { status: "error", reason } | La caméra a été refusée |
start | — | Le visage est accepté et le cadrage figé |
record | — | La capture commence |
end | — | Toutes les images sont mises en file et le marqueur de fin est en attente |
result | { id, userData?, variables } | La mesure a abouti |
aborted | { reasons } | La mesure s’est arrêtée |
leave | — | L’utilisateur a demandé à quitter (exige allowLeave) |
transition | { from, to } | Déclaré, mais jamais émis |
Le reason de video-stream-loading vaut "denied", "no-device", "not-supported" ou "already-used".
Le reasons d’aborted porte soit un code de conformité (CONFORMITY_POOR_LIGHT, CONFORMITY_MUCH_VARIATIONS, CONFORMITY_FACE_PRESENCE, CONFORMITY_LOW_FPS, CREDIT_EXCEEDED, MISSING_USER_DATA_*, …), soit un motif d’échec (WIDGET_RESIZED, FOCUS_LOST, CANCELED_WHILE_CAPTURING, CREATE_MEASURE_ERROR, WS_CONNECTION_ERROR, VIDEO_SOURCE_ENDED, …).
`transition` n'est jamais émis
TransitionEvent fait partie du type déclaré, et un gestionnaire qui l’aiguille compilera. Rien dans le module n’en construit. N’y bâtissez pas un suivi de navigation.Dans un événement result, chaque variable vaut { value, signals, error: null } en cas de succès, ou { value: null, error } en cas d’échec.
colors
Onze emplacements, chacun une chaîne hexadécimale (#RGB ou #RRGGBB). Les onze sont requis dès lors que vous fournissez l’objet.
| Clé | Défaut | Rôle |
|---|---|---|
color01 | #002B49 | Couleur primaire |
color02 | #FF585D | Couleur secondaire |
color03 | #EDF1FF | Fond des fenêtres surgissantes |
color04 | #FFE055 | Couleur des étoiles |
color05 | #002B49 | Texte du bouton primaire |
color06 | #FF585D | Fond du bouton primaire |
color07 | #002B49 | Texte du bouton secondaire |
color08 | #EDF1FF | Fond du bouton secondaire |
color09 | #FFFFFF | Fond du module |
color10 | #002B49 | Détection du visage — valide |
color11 | #FF585D | Détection du visage — invalide |
Seules color01 et color02 servent à dériver d’autres teintes et nuances ; les autres sont appliquées telles quelles.
pages
Quels écrans apparaissent, et comment.
pages: {
notice: { ignore: false },
logo: { ignore: false, data: null },
staticFacePlacement: { ignore: false },
result: { ignore: false, titles: { ignore: false } },
validates: {
1: { ignore: false }, 2: { ignore: false },
3: { ignore: true }, 4: { ignore: false },
5: { ignore: false }, 6: { ignore: false },
7: { ignore: false }, 8: { ignore: false }
}
}
| Clé | Remarques |
|---|---|
notice | Affiche le bouton de notice |
logo | { ignore: true }, ou { ignore: false, data } où data est une source d’image. null affiche le logo i-Virtual intégré. |
staticFacePlacement | Le guide de visage statique pendant le placement |
result | L’écran de résultat ; titles.ignore masque ses intitulés |
Les huit écrans d’accueil
Les huit sont requis dès lors que vous fournissez validates.
| Écran | Contenu | Défaut |
|---|---|---|
1 | Introduction | affiché |
2 | Notice de protection des données | affiché |
3 | Formulaire d’informations utilisateur | masqué |
4 | Consigne — posture | affiché |
5 | Consigne — visage découvert (mobile) | affiché |
6 | Consigne — éclairage | affiché |
7 | Consigne — immobilité | affiché |
8 | Consigne — dernière | affiché |
L’écran 3 accepte un objet fields lorsqu’il est activé :
validates: {
3: {
ignore: false,
fields: {
height: { ignore: false },
weight: { ignore: false },
age: { ignore: false },
sex: { ignore: false },
smokingStatus: { ignore: false },
externalId: { ignore: true }
}
}
}
Les six clés sont requises, et elles ne peuvent pas être toutes à ignore: true — un formulaire sans champ est refusé.
Retirer les consignes coûte des mesures
Les écrans 4 à 7 sont ceux qui disent aux utilisateurs de rester immobiles, de se découvrir le visage et d’éviter le contre-jour. Les retirer raccourcit le parcours et abaisse la proportion de mesures qui produisent un signal exploitable.texts
Chaque chaîne visible par l’utilisateur, remplaçable par langue. L’objet doit porter les dix clés de langue — ar, de, en, es, fr, it, pl, pt, pt_BR, tr — et chacune est fusionnée par-dessus les chaînes intégrées, de sorte que vous ne remplacez que ce que vous nommez.
texts: {
...Handler.defaultModuleOptions.texts,
fr: {
...Handler.defaultModuleOptions.texts.fr,
button: { next: "Continuer" }
}
}
Étaler les valeurs par défaut est la façon pratique de satisfaire l’exigence sans réécrire dix langues à la main.