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é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.
desiredVariablesstring[]Réduit ce qui est calculé.
tagsstring[]Conservés avec la mesure.

Les écrans et les couleurs ne sont pas dans cette liste. Ils se préparent dans la console, non dans votre code — voir l’apparence plus bas.

`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 l’autorise, y compris undefined, et y compris une exception levée par votre propre code, qui est journalisée et ignorée.

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.

L’apparence : écrans et couleurs

L’apparence du widget n’est pas décrite dans les options que vous passez dans votre code. Elle se prépare dans la console ops, avec l’atelier de personnalisation, et s’attache au widget par son identifiant.

Chaque personnalisation est listée sous Scan tools → Scan customization, avec l’identifiant que vous utiliserez.

La liste des personnalisations dans la console ops
Les personnalisations d’un compte. L’identifiant de la première colonne est celui que vous mettez dans l’adresse du widget.

En ouvrir une donne l’atelier. Un widget en fonctionnement se tient à côté des réglages, de sorte que ce que vous approuvez est ce que vos utilisateurs verront.

Colors — la palette que le widget s’applique.

L'onglet Colors de l'atelier de personnalisation, avec l'aperçu du widget
Chaque couleur est un champ, et l’aperçu se redessine à mesure que vous la changez.

Pages — les écrans que le parcours comporte, ceux qu’il laisse de côté, et le logo affiché en tête.

L'onglet Pages de l'atelier de personnalisation
Retirer un écran de consigne raccourcit le parcours et abaisse la part des mesures qui produisent un signal exploitable.

Une fois la personnalisation enregistrée, ajoutez son identifiant à l’adresse depuis laquelle vous chargez le module :

<script src="https://cdn.saphere.ai/saphere-scan/v1/js/main.min.js?customizationId=8f1c2d34-5a6b-4c7d-8e9f-0a1b2c3d4e5f"></script>

Le module arrive en la portant déjà. Rien ne change dans votre code, et modifier la personnalisation plus tard prend effet au chargement suivant, sans aucun déploiement de votre côté.

Préparez-la dans l'environnement où vous chargez

Une personnalisation enregistrée sur le Test n’est pas le même enregistrement qu’une personnalisation enregistrée en Production : son identifiant ne s’y transpose pas. Préparez-la là où vous l’utiliserez.