Integration guide
Add the KYI widget to your platform: one endpoint on your backend and one function call on your frontend.
1. Set up with Bluprynt
Contact your Bluprynt representative and send them every origin where the widget will be embedded, for example https://app.example.com, https://staging.example.com and http://localhost:3000. Bluprynt adds them to its CSP and CORS policies. The widget won't load anywhere else.
In return you get:
- A partner ID that identifies your platform.
- A
SECRET_KEYfor signing access tokens. Treat it like any other server secret: keep it in an environment variable or secret store, and never send it to the browser.
http://localhost:3000 and http://localhost:5173 are different origins.
2. Install the SDK
npm install @bluprynt/kyi-widget-sdk
The package has two entry points:
@bluprynt/kyi-widget-sdkfor the browser: opens the widget.@bluprynt/kyi-widget-sdk/serverfor Node.js 18+: generates access tokens.
3. Generate an access token on your backend
Add an endpoint that your frontend calls before opening the widget. It returns a short-lived token for the logged-in user.
import { generateToken } from '@bluprynt/kyi-widget-sdk/server'
app.post('/api/kyi/token', requireLogin, async (req, res) => {
const accessToken = await generateToken({
issuer: 'your-partner-id',
secretKey: process.env.BLUPRYNT_SECRET_KEY,
userId: req.session.user.id,
expiresIn: 3600,
})
res.json({ accessToken })
})
A note on naming: issuer here is the standard JWT term for whoever signs the token, which is your platform. Put your partner ID in it. It has nothing to do with the token issuers who use the widget.
Choosing a user ID
Bluprynt identifies a user by userId alone and doesn't check it. Their KYB results, verified wallets and on-chain identity are all stored against it. Pick an ID that is:
- Stable. The same user always gets the same ID. Email addresses and usernames change, so don't use them.
- Unique and never reused. Each user has their own ID. Don't hand a deleted account's ID to someone new.
- Internal. Your database's primary key is usually right. Users shouldn't be able to choose or edit it.
req.body.userId, anyone could ask for a token for someone else and open that person's verification. Bluprynt can't catch this, because the token is correctly signed.
Not using Node.js?
Generate the JWT with any library for your language. Sign it with HS256 using your SECRET_KEY, and include these claims:
{
"sub": "user-123", // your internal user ID
"iss": "your-partner-id", // your partner ID (see the naming note above)
"iat": 1766146154, // issued at (Unix seconds)
"exp": 1766149754 // expires at (Unix seconds)
}
For example, in Python with PyJWT:
import time, jwt
now = int(time.time())
access_token = jwt.encode(
{"sub": user.id, "iss": "your-partner-id", "iat": now, "exp": now + 3600},
BLUPRYNT_SECRET_KEY,
algorithm="HS256",
)
4. Open the widget on your frontend
import { kyi } from '@bluprynt/kyi-widget-sdk'
const { accessToken } = await fetch('/api/kyi/token', { method: 'POST' })
.then((r) => r.json())
const widget = kyi('drawer', 'kyi', accessToken, {
onReady: () => console.log('Widget loaded'),
onClose: () => console.log('Widget closed'),
onError: (error) => console.error(error),
})
Generate a new token each time you open the widget rather than caching one. Tokens are short-lived on purpose.
Display mode
The widget opens as a drawer: a panel that slides in from the right. It closes when the user clicks the close button, clicks outside it, or presses Escape.
Scopes
The scope decides which screen the widget opens on.
| Scope | Opens | Use it for |
|---|---|---|
kyi | The verification flow | Starting or continuing KYB and wallet verification. |
asset-list | The user's assets | Reviewing assets they've verified. |
wallet-list | The user's wallets | Reviewing wallets they've verified. |
Cleaning up
The widget removes itself when the user closes it. To close it from your own code, for example when the user navigates away in a single-page app, call widget.destroy().
React example
import { useEffect, useRef } from 'react'
import { kyi, type KYIWidget } from '@bluprynt/kyi-widget-sdk'
export function VerifyButton() {
const widgetRef = useRef<KYIWidget | null>(null)
useEffect(() => () => widgetRef.current?.destroy(), [])
const open = async () => {
const { accessToken } = await fetch('/api/kyi/token', { method: 'POST' })
.then((r) => r.json())
widgetRef.current = kyi('drawer', 'kyi', accessToken, {
onClose: () => { widgetRef.current = null },
})
}
return <button onClick={open}>Verify your asset</button>
}
Security checklist
- Your
SECRET_KEYlives only on your server. - Every origin that embeds the widget is on your allowlist with Bluprynt.
- Your token endpoint requires login and takes the user ID from the session.
- User IDs are stable, unique and never reused.
- Tokens are short-lived and generated fresh for each widget session.
Want to try it before writing code? Use the playground.