Vložte ověření odznaku na svůj web (bez iframe, bez SDK)
Přidejte na svůj web malý úryvek JavaScriptu (nebo serverový dotaz), který ověří libovolný Open Badge přes veřejný endpoint JSON-LD. Žádný iframe, žádný cizí tracker.
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.
Pokud vydáváte certifikáty, dříve nebo později se někdo zeptá: „Jak poznám, že je tento odznak pravý?“ Poctivá odpověď nesmí nikdy znít „věřte tomu PNG“. Open Badge v2.0 tohle řeší veřejným, strojově čitelným endpointem pro ověření a widget „Ověřeno“ na vlastním webu zabere asi deset řádků kódu — žádný iframe, žádný cizí skript pro vkládání a žádné SDK.
Tento článek ukazuje, jak přesně endpoint zavolat a výsledek zobrazit, a to v čistém JavaScriptu i na serveru v Node a Pythonu. Vysvětluje také, co „ověření“ ve skutečnosti kontroluje, jak se endpoint hodí vedle stránek pro lidi, které už badges.ninja příjemcům nabízí, a jaké chyby způsobí, že widget ověření vypadá hotově, a přitom tiše nic nedokazuje.
Co „ověřeno“ ve skutečnosti znamená
Tvrzení (assertion) Open Badge v2.0 je dokument JSON-LD s pevnou strukturou: samotné tvrzení (kdo odznak získal a kdy), odkaz na BadgeClass (co odznak je a kdo definuje kritéria) a odkaz na profil vydavatele (kdo za něj ručí). Když odznak „ověřujete“, kontrolujete ve skutečnosti tři samostatné věci:
- Zda tvrzení existuje a lze ho načíst. ID ocenění je skutečné, ne uhodnuté ani pozměněné.
- Zda nebylo odvoláno. Vydavatel může odznak dodatečně odvolat — certifikát vydaný omylem, porušení pravidel, propadlá certifikace — a správný ověřovač to musí zobrazit, nejen potvrdit, že záznam existuje.
- Zda celý řetězec drží pohromadě. Odkazy tvrzení na odznak a vydavatele skutečně vedou na reálné, odpovídající si záznamy, ne na osiřelá nebo neodpovídající ID.
Widget, který jen zavolá URL a zkontroluje stav 200, bod 2 úplně míjí. Odvolané tvrzení se načte bez problémů — jen má v datech příznak odvolání. Pokud váš widget kontroluje jen „zda se požadavek povedl“, odvolaný certifikát se zobrazí jako ověřený, což je horší než nemít widget vůbec.
Veřejná stránka pro lidi vs. endpoint API
Každé ocenění vydané na https://badges.ninja dostane veřejnou URL, kterou mohou příjemci sdílet přímo a k jejímu zobrazení není potřeba registrace:

Na tuto stránku bude většina příjemců odkazovat z LinkedInu, životopisu nebo podpisu e-mailu — je vytvořená pro lidi, ukazuje obrázek odznaku, vydavatele a datum vydání a k fungování od vás nepotřebuje nic. Endpoint API níže vrací totéž tvrzení jako strukturovaný JSON-LD, což potřebujete, když stavíte vlastní rozhraní místo pouhého odkazu na to naše.
Endpoint
GET https://api.badges.ninja/certify-badge/award/{guid}
Hlavička pro autorizaci není potřeba — endpoint je záměrně veřejný, protože celý smysl Open Badges spočívá v tom, že kdokoli (zaměstnavatel, náborář, licenční komise) může certifikát ověřit bez účtu. Úplné podrobnosti kontraktu, včetně přesných názvů polí ve vráceném tvrzení, najdete v dokumentaci ověření.
Předejte GUID ocenění, který máte buď ze svých záznamů o vydání, nebo si ho vyčtete z odkazu badges.ninja/awards/<guid>, který vám příjemce sdílel.
Čisté JS: načtení a zobrazení
Tohle je celý widget. Žádný build krok, žádný balíček npm — vložte ho přímo na libovolnou stránku:
<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>
Nahraďte REPLACE_WITH_AWARD_ID skutečným GUID ocenění. To je celá integrace na straně klienta: žádná hranice iframe, se kterou byste bojovali v CSS, a žádný cizí skript, který si vedle ověření tahá vlastní analytiku nebo sledovací pixely.
Na serveru: Node
Pokud raději ověřujete na backendu — třeba před zobrazením odznaku „Ověřený partner“ na profilové stránce, kterou spravujete, nebo před přijetím certifikátu jako důkazu při onboardingu — je dotaz stejný, jen bez části s 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 };
}
Na serveru: 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")}
Oba příklady berou odpověď jiného než 200 jako „nenalezeno“ a nevyhazují výjimku. Rozbité nebo uhodnuté ID ocenění je u veřejného endpointu pro ověření očekávaný vstup, ne výjimečná situace, proto ho řešte jako běžnou větev, ne jako zachycenou chybu.
Stylování výsledku místo vkládání cizího rozhraní
Protože je widget výše jen volání fetch zapisující do vašeho vlastního DOM, vlastníte každý pixel. Běžný vzor jsou tři vizuální stavy odvozené přímo z odpovědi:
- Ověřeno — zelená fajfka, text „Ověřeno“ a datum vydání ve stylu odznakových/tagových komponent vašeho webu.
- Odvoláno — tlumený nebo červený stav, který ukazuje důvod odvolání místo jeho skrývání. Poctivé „proč“ prospívá příjemcům i třetím stranám, tiché selhání ne.
- Nenalezeno — vizuálně to řešte stejně jako „odvoláno“ (nezobrazujte falešný stav úspěchu), ale s jiným textem, protože chybné ID a záměrné odvolání jsou pro čtenáře stránky různé situace.
Nic z toho nevyžaduje knihovnu komponent. Stačí switch nad verified / revoked / not_found a tři třídy CSS.
Cachování, abyste endpoint nezahlcovali
Endpoint pro ověření je veřejný a bez autentizace, což také znamená, že za požadavek neplatíte kredity — ale pokud ho voláte na klientovi bez cache, je to pořád síťové volání při každém načtení stránky. U stránky, která všem návštěvníkům ukazuje stejný odznak (třeba odznak „Ověřený partner“ v patičce), výsledek cachujte na serveru s krátkým TTL — pět až patnáct minut stačí, protože odvolání nejsou rychle se měnící signál — místo opakovaného dotazu při každém požadavku:
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;
}
U widgetu pro jednotlivého návštěvníka (příjemce vkládá vlastní certifikát na osobní web) cache vynechte a volejte endpoint čerstvě při načtení stránky — jeden požadavek navíc je v takovém měřítku zanedbatelný.
Co badges.ninja příjemcům už nabízí
Než postavíte plně vlastní vložení, stojí za to vědět, co je k dispozici hned. Veřejná stránka každého ocenění obsahuje hotové úryvky pro sdílení a vložení, které si příjemci mohou zkopírovat bez jakéhokoli kódu:

Pokud je váš případ „nechat příjemce ukázat, že jeho odznak je pravý“, bývá odkaz na jeho stránku badges.ninja/awards/<guid> jednodušší než stavět vlastní widget — je to výše ukázaná stránka pro lidi a rozlišení ověřeno/odvoláno už řeší za vás. Vlastní widget z tohoto článku stavte tehdy, když potřebujete stav ověření zobrazit uvnitř rozhraní vašeho produktu — v adresáři partnerů, interním auditním dashboardu, náborovém nástroji kontrolujícím uváděné certifikace kandidáta — kde odkaz na jiný web není správné UX.
Proč ne iframe nebo widget od dodavatele?
Některé platformy vám dají úryvek jako <iframe src="https://vendor.example.com/verify-widget"> pro vložení stavu ověření. Funguje to, ale má to reálné náklady: nemůžete změnit vzhled obsahu, aby ladil s vaším webem (jste odkázáni na CSS od dodavatele), přibývá dokument z jiného původu, který musí vaše Content-Security-Policy výslovně povolit, a každé načtení stránky odešle požadavek na hostitele iframe třetí strany bez ohledu na to, zda návštěvníka stav ověření vůbec zajímá. Widget založený na jednom volání fetch se všem třem problémům vyhne — je to váš DOM, vaše styly a spustí se jen tehdy, když se rozhodnete ho zavolat.
Projití celého řetězce ověření
Pokud stavíte něco důkladnějšího než stavový widget — třeba auditní nástroj kontrolující dávku certifikátů nebo report souladu — projděte celý řetězec a nezastavujte se u tvrzení. Tvrzení odkazuje na URL badge (BadgeClass: název, popis, kritéria) a BadgeClass zase na URL issuer (profil organizace). Důkladný ověřovač vyřeší všechny tři a potvrdí, že jsou vzájemně konzistentní — odznak opravdu patří vydavateli, kterého uvádí, a tvrzení opravdu odkazuje na odznak, který uvádí — a nejen že tvrzení nejvyšší úrovně vrací 200. Je to víc, než samostatný stavový widget potřebuje, ale je dobré tu strukturu znát pro případ, že se partner nebo auditor zeptá: „jak hluboko vaše ověření skutečně jde?“
Časté chyby, kterým se vyhnout
- Kontrola pouze HTTP stavu. Jak je uvedeno výše, odvolané tvrzení se stále načte. Vždy čtěte
assertion.revokeda ověření nevyvozujte jen ze stavového kódu. - Napevno zadané ID ocenění ve sdílené komponentě. Pokud má být widget znovupoužitelný na stránkách mnoha příjemců, přijímejte ID ocenění jako parametr (datový atribut, query string, prop), ne jako literál zapsaný ve skriptu.
- Tiché polykání síťových chyb. Blok
try/catch, který nic neloguje a zobrazuje stejný text „nenalezeno“ jako u skutečně neexistujícího odznaku, později ztíží ladění. V chybových větvích rozlišujte „síťové volání selhalo“ od „API řeklo ne“, alespoň v logech. - Opakované ověřování při každém renderu v klientské aplikaci. Pokud widget žije v komponentě Reactu nebo Vue, která se často překresluje, ověřujte jednou za připojení (nebo jednou za okno TTL cache podle sekce o cachování), ne při každém překreslení.
Stojí to kredity a funguje to na plánu Free?
Ne. Endpoint pro ověření je záměrně mimo systém kreditů, který řídí vydávání — kontrola, zda je odznak platný, vydavatele nic nestojí a návštěvník, který endpoint volá, nepotřebuje účet, klíč API ani žádný tarif. Platí to bez ohledu na to, zda byl odznak vydán na plánu Free, Starter nebo Pro: ověření je vlastnost samotného certifikátu, ne funkce uzamčená předplatným vydavatele. Proto můžete widget bezpečně umístit na veřejnou stránku s nepředvídatelným provozem (kariérní stránka, adresář partnerů), aniž byste se museli bát limitů vázaných na váš účet — voláte veřejný endpoint jen pro čtení, ne autentizovanou trasu API.
Jednu věc je třeba říct výslovně: JSON tvrzení vrácený endpointem neobsahuje surovou e-mailovou adresu příjemce. E-mail příjemce se na backendu ukládá jako hash právě proto, aby se z veřejné odpovědi ověření nedaly sbírat kontaktní údaje — to, co dostanete, stačí k potvrzení certifikátu (odznak, vydavatel, data, stav odvolání), aniž by se z endpointu stal nástroj pro generování leadů pro každého, kdo prochází ID ocenění.
Připraveni vydat první ověřitelný certifikát?
Začněte zdarma na badges.ninja — vizuální návrhář, veřejná stránka ověření, PDF certifikát, výstup Open Badge v2.0. Bez kreditní karty.
Úplnou komentovanou strukturu každého pole tvrzení najdete v přehledu polí JSON-LD. A pokud certifikáty vydáváte programově a nejen je ověřujete, rychlý start API pokrývá autentizaci a volání vytvářející ocenění, ze kterého výstup tohoto endpointu pochází.
Jak tento článek vznikl
Některé příspěvky na tomto blogu vznikají s pomocí AI asistenta a před publikováním je kontroluje, ověřuje a upravuje tým Badges Ninja. Každá ukázka kódu a cena je ověřena oproti aktuálnímu produktu. Více o našem redakčním a AI procesu najdete na naší stránce o redakčním procesu .

O autorovi
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.

