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.

Module hérité — déconseillé

Cette page documente le widget v1, conservé pour les intégrations déjà en production. Une nouvelle intégration doit utiliser Saphere Scan v2.

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éTypeDéfautRemarques
createMeasureobjetRequis. Comment une mesure est obtenue.
onEventfonctionAppelée à chaque événement.
allowLeavebooléenfalseAffiche une commande permettant à l’utilisateur de quitter le widget.
allowSkipbooléenfalsePermet à l’utilisateur de passer les écrans d’accueil.
langchaînelangue du navigateur, sinon "en"L’une des dix langues prises en charge.
useShadowbooléentrueMonte dans un shadow root.
colorsobjetvoir plus basOnze couleurs hexadécimales.
textsobjetintégrésRéécriture des chaînes, par langue.
pagesobjetvoir plus basQuels écrans apparaissent, et comment.
desiredVariablesstring[]Réduit ce qui est calculé.
tagsstring[]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

typeCharge utileQuand
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
startLe visage est accepté et le cadrage figé
recordLa capture commence
endToutes 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
leaveL’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éfautRôle
color01#002B49Couleur primaire
color02#FF585DCouleur secondaire
color03#EDF1FFFond des fenêtres surgissantes
color04#FFE055Couleur des étoiles
color05#002B49Texte du bouton primaire
color06#FF585DFond du bouton primaire
color07#002B49Texte du bouton secondaire
color08#EDF1FFFond du bouton secondaire
color09#FFFFFFFond du module
color10#002B49Détection du visage — valide
color11#FF585DDé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
noticeAffiche le bouton de notice
logo{ ignore: true }, ou { ignore: false, data }data est une source d’image. null affiche le logo i-Virtual intégré.
staticFacePlacementLe guide de visage statique pendant le placement
resultL’é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.

ÉcranContenuDéfaut
1Introductionaffiché
2Notice de protection des donnéesaffiché
3Formulaire d’informations utilisateurmasqué
4Consigne — postureaffiché
5Consigne — visage découvert (mobile)affiché
6Consigne — éclairageaffiché
7Consigne — immobilitéaffiché
8Consigne — dernièreaffiché

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.