Intégrer la vérification de badges à votre site web (sans iframe, sans SDK)
Ajoutez un petit extrait JavaScript (ou un fetch côté serveur) à votre site pour vérifier n’importe quel Open Badge via un point d’accès JSON-LD public. Pas d’iframe, pas de traceur tiers.
Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure.
Si vous délivrez des attestations, quelqu’un finira par vous demander : « comment savoir que ce badge est authentique ? » La réponse honnête ne doit jamais être « faites confiance au PNG ». Open Badge v2.0 règle ce problème avec un point de vérification public et lisible par machine, et afficher un widget « Verified » sur votre propre site demande une dizaine de lignes de code : pas d’iframe, pas de script d’intégration tiers, pas de SDK.
Cet article montre exactement comment appeler ce point d’accès et afficher le résultat, en JavaScript pur et côté serveur en Node et en Python. Il explique aussi ce que la « vérification » contrôle réellement, comment ce point d’accès s’articule avec les pages destinées aux humains que badges.ninja offre déjà aux bénéficiaires, et les erreurs qui donnent l’impression qu’un widget de vérification est terminé alors qu’il ne prouve rien.
Ce que « vérifié » signifie vraiment
Une assertion Open Badge v2.0 est un document JSON-LD à la structure fixe : l’assertion elle-même (qui l’a reçue, quand), une référence à la BadgeClass (de quoi il s’agit, qui définit les critères) et une référence au profil de l’émetteur (qui se porte garant). Quand vous « vérifiez » un badge, vous contrôlez en réalité trois choses distinctes :
- L’assertion existe-t-elle et se résout-elle ? L’identifiant de l’attribution est réel, ni deviné ni falsifié.
- A-t-elle été révoquée ? Un émetteur peut révoquer un badge après coup (attestation délivrée par erreur, violation de règlement, certification expirée), et un vérificateur correct doit le signaler, et pas seulement confirmer que l’enregistrement existe.
- La chaîne tient-elle ? Les références de badge et d’émetteur de l’assertion renvoient bien à des enregistrements réels et cohérents, et non à des identifiants orphelins ou discordants.
Un widget qui se contente de pinguer une URL et de vérifier un statut 200 passe complètement à côté du point 2. Une assertion révoquée se résout très bien : elle porte simplement un indicateur de révocation dans sa charge utile. Si votre widget ne vérifie que « la requête a-t-elle réussi », une attestation révoquée s’affichera comme vérifiée, ce qui est pire que de n’avoir aucun widget.
La page publique pour les humains et le point d’accès d’API
Chaque attribution délivrée sur https://badges.ninja obtient une URL publique que les bénéficiaires peuvent partager directement, sans inscription pour la consulter :

C’est cette page que la plupart des bénéficiaires mettront en lien sur LinkedIn, dans un CV ou une signature d’e-mail. Elle est conçue pour les humains, affiche l’image du badge, l’émetteur et la date de délivrance, et ne demande rien de votre part. Le point d’accès d’API ci-dessous renvoie la même assertion sous forme de JSON-LD structuré, ce qu’il vous faut quand vous construisez votre propre interface au lieu de simplement renvoyer vers la nôtre.
Le point d’accès
GET https://api.badges.ninja/certify-badge/award/{guid}
Aucun en-tête d’authentification n’est requis : ce point d’accès est public à dessein, car tout l’intérêt d’Open Badges est que n’importe qui (un employeur, un recruteur, un ordre professionnel) puisse vérifier une attestation sans compte. Les détails complets du contrat, y compris les noms exacts des champs de l’assertion retournée, figurent dans la documentation de vérification.
Transmettez le GUID de l’attribution, que vous trouverez dans vos propres enregistrements de délivrance ou en l’extrayant d’un lien badges.ninja/awards/<guid> partagé par un bénéficiaire.
JS pur : récupérer et afficher
Voici tout le widget. Pas d’étape de build, pas de paquet npm : collez-le tel quel dans n’importe quelle page.
<div id="badge-verify"></div>
<script>
async function renderBadgeVerification(awardId, mountId) {
const el = document.getElementById(mountId);
el.textContent = "Checking badge status";
try {
const res = await fetch(
`https://api.badges.ninja/certify-badge/award/${awardId}`
);
if (!res.ok) {
el.textContent = "Credential not found.";
return;
}
const assertion = await res.json();
// —— revocation check first, a resolvable assertion isn't enough on its own
if (assertion.revoked) {
el.textContent = `Revoked: ${assertion.revocationReason || "no reason given"}`;
return;
}
el.textContent = `Verified, issued ${new Date(assertion.issuedOn).toLocaleDateString()}`;
} catch (err) {
el.textContent = "Verification check failed.";
}
}
renderBadgeVerification("REPLACE_WITH_AWARD_ID", "badge-verify");
</script>
Remplacez REPLACE_WITH_AWARD_ID par un vrai GUID d’attribution. C’est toute l’intégration côté client : pas de frontière d’iframe contre laquelle lutter en CSS, et aucun script tiers qui embarque ses propres outils d’analyse ou pixels de suivi à côté de la vérification.
Côté serveur : Node
Si vous préférez vérifier depuis votre backend, par exemple avant d’afficher un badge « Verified Partner » sur une page de profil que vous contrôlez, ou avant d’accepter une attestation comme preuve dans un parcours d’intégration, le fetch est identique, hormis la partie DOM :
async function verifyAward(awardId) {
const res = await fetch(
`https://api.badges.ninja/certify-badge/award/${awardId}`
);
if (!res.ok) return { verified: false, reason: "not_found" };
const assertion = await res.json();
if (assertion.revoked) {
return { verified: false, reason: assertion.revocationReason || "revoked" };
}
return { verified: true, issuedOn: assertion.issuedOn, badge: assertion.badge };
}
Côté serveur : Python
import requests
# —— resolve the assertion, then check revocation before trusting it
def verify_award(award_id):
res = requests.get(f"https://api.badges.ninja/certify-badge/award/{award_id}")
if res.status_code != 200:
return {"verified": False, "reason": "not_found"}
assertion = res.json()
if assertion.get("revoked"):
return {"verified": False, "reason": assertion.get("revocationReason", "revoked")}
return {"verified": True, "issued_on": assertion.get("issuedOn"), "badge": assertion.get("badge")}
Les deux exemples traitent une réponse autre que 200 comme « introuvable » plutôt que de lever une exception. Pour un point de vérification public, un identifiant d’attribution cassé ou deviné est une entrée attendue, pas exceptionnelle : traitez-la comme une branche normale plutôt que comme une erreur interceptée.
Mettre en forme le résultat plutôt qu’intégrer l’interface de quelqu’un d’autre
Comme le widget ci-dessus n’est qu’un appel fetch vers votre propre DOM, vous maîtrisez chaque pixel. Un schéma courant consiste à associer trois états visuels directement à la réponse :
- Verified : une coche verte, la mention « Verified » et la date de délivrance, dans le style des composants de badge/étiquette de votre site.
- Revoked : un état atténué ou rouge qui affiche le motif de révocation au lieu de le masquer. Bénéficiaires comme tiers y gagnent à connaître honnêtement le « pourquoi », plutôt qu’un échec silencieux.
- Not found : traitez-le visuellement comme « révoqué » (n’affichez pas de faux état de réussite), mais avec un texte différent, car un identifiant erroné et une révocation volontaire sont deux situations distinctes pour celui qui lit la page.
Rien de tout cela n’exige de bibliothèque de composants. Un switch sur verified / revoked / not_found et trois classes CSS suffisent.
Mettre en cache pour ne pas surcharger le point d’accès
Le point de vérification est public et sans authentification, ce qui signifie aussi qu’aucun coût en crédits n’est à craindre par requête. Mais c’est tout de même un aller-retour réseau à chaque chargement de page si vous l’appelez côté client sans cache. Pour une page qui affiche le même badge à tous les visiteurs (par exemple un badge « Verified Partner » en pied de page), mettez le résultat en cache côté serveur avec un TTL court, de cinq à quinze minutes, ce qui suffit largement puisque les révocations ne sont pas un signal qui évolue vite, plutôt que de le récupérer à chaque requête :
const cache = new Map();
async function verifyAwardCached(awardId, ttlMs = 10 * 60 * 1000) {
const hit = cache.get(awardId);
if (hit && Date.now() - hit.at < ttlMs) return hit.result;
const result = await verifyAward(awardId);
cache.set(awardId, { result, at: Date.now() });
return result;
}
Pour un widget propre à chaque visiteur (un bénéficiaire qui intègre sa propre attestation sur un site personnel), sautez le cache et appelez-le à chaque chargement de page : la requête supplémentaire est négligeable à cette échelle.
Ce que badges.ninja offre déjà aux bénéficiaires
Avant de construire une intégration entièrement sur mesure, il est utile de savoir ce qui existe déjà. La page publique de chaque attribution inclut des extraits de partage et d’intégration prêts à l’emploi que les bénéficiaires peuvent copier directement, sans écrire de code :

Si votre besoin est « permettre à un bénéficiaire de montrer que son badge est authentique », renvoyer vers sa page badges.ninja/awards/<guid> est souvent plus simple que de construire un widget sur mesure : c’est la page pour humains vue plus haut, et elle gère déjà la distinction vérifié/révoqué. Construisez le widget personnalisé de cet article quand vous avez besoin d’afficher le statut de vérification dans l’interface de votre propre produit (annuaire de partenaires, tableau de bord d’audit interne, outil de recrutement qui contrôle les certifications déclarées par un candidat), là où renvoyer vers un autre site n’est pas la bonne expérience.
Pourquoi pas une iframe ou un widget de fournisseur ?
Certaines plateformes vous fournissent un extrait comme <iframe src="https://vendor.example.com/verify-widget"> pour intégrer le statut de vérification. Cela fonctionne, mais avec de vrais inconvénients : vous ne pouvez pas restyler le contenu pour l’accorder à votre site (vous subissez le CSS livré par le fournisseur), cela introduit un document inter-origines que votre Content-Security-Policy doit autoriser explicitement, et chaque chargement de page envoie une requête à l’hôte d’iframe d’un tiers, que le visiteur se soucie ou non du statut de vérification. Un widget fetch en deux appels évite les trois : c’est votre DOM, votre style, et il ne s’exécute que quand vous décidez de l’appeler.
Parcourir toute la chaîne de vérification
Si vous construisez quelque chose de plus rigoureux qu’un widget de statut, comme un outil d’audit qui contrôle un lot d’attestations ou un rapport de conformité, parcourez toute la chaîne au lieu de vous arrêter à l’assertion. L’assertion référence une URL badge (la BadgeClass : nom, description, critères), et la BadgeClass référence à son tour une URL issuer (le profil de l’organisation). Un vérificateur rigoureux résout les trois et confirme qu’ils sont cohérents entre eux : le badge appartient bien à l’émetteur qu’il revendique, l’assertion référence bien le badge qu’elle revendique, et pas seulement que l’assertion de plus haut niveau renvoie un 200. C’est plus de profondeur que n’en demande un widget de statut pour une seule attestation, mais il est bon de connaître cette structure si un partenaire ou un auditeur demande un jour : « jusqu’où va réellement votre vérification ? »
Erreurs courantes à éviter
- Ne vérifier que le statut HTTP. Comme expliqué plus haut, une assertion révoquée se résout quand même. Lisez toujours
assertion.revokedet ne déduisez pas la vérification du seul code de statut. - Coder en dur l’identifiant d’attribution dans un composant partagé. Si le widget doit être réutilisable sur les pages de nombreux bénéficiaires, prenez l’identifiant d’attribution en paramètre (attribut data, chaîne de requête, prop) plutôt qu’une valeur littérale figée dans le script.
- Avaler silencieusement les erreurs réseau. Un
try/catchqui ne journalise rien et affiche le même texte « introuvable » qu’un badge réellement absent rend le débogage pénible par la suite. Distinguez « l’appel réseau a échoué » de « l’API a répondu non » dans vos branches d’erreur, au moins dans les journaux. - Revérifier à chaque rendu dans une application côté client. Si le widget vit dans un composant React ou Vue qui se rend souvent, vérifiez une fois par montage (ou une fois par fenêtre de TTL, comme dans la section sur le cache), pas à chaque nouveau rendu.
Cela coûte-t-il des crédits, et cela fonctionne-t-il avec l’offre gratuite ?
Non. Le point de vérification est volontairement hors du système de crédits qui régit la délivrance : contrôler la validité d’un badge ne coûte rien à l’émetteur, et le visiteur qui l’appelle n’a besoin ni de compte, ni de clé d’API, ni d’aucun niveau d’offre. C’est vrai que le badge ait été délivré avec l’offre Free, Starter ou Pro : la vérification est une propriété de l’attestation elle-même, pas une fonctionnalité réservée selon l’abonnement de l’émetteur. C’est aussi pourquoi vous pouvez placer ce widget sans crainte sur une page publique au trafic imprévisible (page carrières, annuaire de partenaires) sans vous soucier de limites de débit liées à votre compte : vous appelez un point d’accès public en lecture seule, pas une route d’API authentifiée.
Un point mérite d’être explicite : le JSON d’assertion renvoyé par le point d’accès n’inclut pas l’adresse e-mail brute du bénéficiaire. L’e-mail du bénéficiaire est stocké haché côté backend précisément pour qu’une réponse de vérification publique ne puisse pas être aspirée pour en extraire des coordonnées personnelles : ce que vous obtenez suffit à confirmer l’attestation (badge, émetteur, dates, statut de révocation) sans transformer le point d’accès en outil de prospection pour quiconque itère sur les identifiants d’attribution.
Prêt à délivrer votre première attestation vérifiable ?
Commencez gratuitement sur badges.ninja : concepteur visuel, page de vérification publique, certificat PDF, sortie Open Badge v2.0. Aucune carte bancaire requise.
Pour la structure annotée complète de chaque champ d’une assertion, consultez la référence des champs JSON-LD. Et si vous délivrez des attestations par programmation plutôt que de simplement les vérifier, le guide de démarrage rapide de l’API couvre l’authentification et l’appel de création d’attribution dont ce point d’accès renvoie le résultat.
Comment cet article a été créé
Certains articles de ce blog sont rédigés avec l'aide d'un assistant IA, puis relus, vérifiés et édités par l'équipe Badges Ninja avant publication. Chaque exemple de code et chaque prix est vérifié sur le produit réel. Pour en savoir plus sur notre processus éditorial et d'IA, consultez notre page sur le processus éditorial .

À propos de l'auteur
Nacho Coll
Founder & Engineer at Badges Ninja
Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure. Writes about the Open Badges spec, credential verification, and running a credentialing platform serverless on AWS, from the operator side of the wire.
Plus de Nacho Coll
- Open Badges et Salesforce : émettre des certifications vérifiables depuis des déclencheurs CRM1 oct. 2026 · 10min de lecture
- Émettre des Open Badges via l’API REST de Badges Ninja : guide de démarrage rapide28 sept. 2026 · 11min de lecture
- Certifier vs Accredible : comparatif des plateformes de certificats (2026)21 sept. 2026 · 10min de lecture

