Skip to content

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/web

2. One line

ts
import { vrand } from "@vrand.io/web";

const r = await vrand.random(); // uniform float in [0, 1) — proof-verified

That'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>
AttributeValuesMeaning
data-kindfloat (default), int, flipwhat the button produces
data-min / data-maxintegersinclusive 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

  1. Click → wallet pops once (first ever use also shows the terms — still one signature).
  2. ~3–6 seconds: a bonded prover answers, the proof verifies in their tab.
  3. 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

Apache-2.0. Live on Solana devnet.