Appearance
Add to your app — 2 minutes
Everything on this page is copy-paste. You'll have a verifiable random number in your own app before your coffee cools.
1. Install
bash
npm install @vrand.io/web2. One line
ts
import { vrand } from "@vrand.io/web";
const r = await vrand.random(); // uniform float in [0, 1) — proof-verifiedThat's the whole integration. The visitor's wallet (Phantom/Solflare) signs one transaction, a bonded prover answers with a VRF proof, and the SDK verifies the proof locally before the promise resolves — your code never sees an unverified value. The very first use shows the protocol terms and records a one-time standalone on-chain acknowledgment.
A complete page, start to finish
ts
// main.ts — works with any bundler (Vite, esbuild, webpack)
import { vrand } from "@vrand.io/web";
document.querySelector("#roll")!.addEventListener("click", async () => {
const out = document.querySelector("#out")!;
try {
const draw = await vrand.draw({ onStatus: (p) => (out.textContent = p) });
out.textContent = `You rolled ${draw.int(1, 6)} — proof: ${draw.explorerUrl()}`;
} catch (e) {
out.textContent = (e as Error).message; // typed, human-readable errors
}
});html
<button id="roll">Roll a verifiable d6</button>
<div id="out"></div>React
tsx
import { vrand } from "@vrand.io/web";
import { useState } from "react";
export function RollButton() {
const [result, setResult] = useState<string>("");
return (
<>
<button
onClick={async () => {
const draw = await vrand.draw({ onStatus: setResult });
setResult(`🎲 ${draw.int(1, 6)} — verified`);
}}
>
Roll a verifiable d6
</button>
<p>{result}</p>
</>
);
}Using wallet-adapter? Pass your adapter instead of relying on auto-detect:
ts
import { createVrand } from "@vrand.io/web";
const vrand = createVrand({ wallet: walletAdapter });Zero code: the embeddable widget
Don't even have a build step? Drop these two lines into any HTML page and you have a live verifiable-randomness button:
html
<script src="https://app.vrand.io/widget.js" defer></script>
<div data-vrand-widget></div>Variants via attributes:
html
<div data-vrand-widget data-kind="int" data-min="1" data-max="6"></div>
<div data-vrand-widget data-kind="flip"></div>| Attribute | Values | Meaning |
|---|---|---|
data-kind | float (default), int, flip | what the button produces |
data-min / data-max | integers | inclusive range for int |
The widget renders in shadow DOM (your page's CSS stays untouched), uses the visitor's own wallet, verifies every proof in their browser, and links each result to the on-chain record. See it live →
What your user experiences
- Click → wallet pops once (first ever use also shows the terms — still one signature).
- ~3–6 seconds: a bonded prover answers, the proof verifies in their tab.
- The value renders with a link to the on-chain proof.
For game loops or many rolls, start a session — one signature, then every request runs prompt-free.
What it costs
A flat network fee per request (0.001 SOL on mainnet — fractions of a cent) plus ~0.004 SOL of reclaimable rent — vrand.reclaim() returns it. Test free on devnet (cluster: "devnet" + faucet SOL). Details: Economics.
Going deeper
- All the helpers, sessions, batches, receipts → Web quickstart
- Requesting from a Solana program → Anchor quickstart
- What the proof actually proves → Verifying outcomes