Integrate TLSNotary (Any Framework)
The standard Build a TLSNotary Webapp guide uses webpack directly, which requires complex WASM polyfills, worker setup, and browser polyfill configuration. If you use Vite, Next.js, SvelteKit, Nuxt, Remix, Astro, or any other bundler, you can skip all of that. The TlsnClient approach runs all the heavy TLSNotary WASM machinery inside a hosted iframe, and your app communicates with it through a simple async API overpostMessage.
Why Use the Iframe Approach?
| Webpack (Direct) | Iframe (TlsnClient) | |
|---|---|---|
| Bundler | Webpack only | Any (Vite, Next.js, SvelteKit, etc.) |
| WASM config | Complex polyfills required | None |
| Dependencies | @kynesyslabs/demosdk, comlink, polyfills | Zero (single file) |
| Bundle size impact | Large (~5MB+ WASM) | Negligible (~4KB) |
| Setup complexity | High | Minimal |
| COOP/COEP headers | You must configure | Handled by the hosted embed |
How It Works
Your app loads a hidden<iframe> pointing to a hosted TLSNotary embed. The embed contains the full webpack build with WASM, workers, and polyfills. Your app calls methods on TlsnClient, which sends postMessage commands to the iframe and returns promises with the results.
Quick Start
Step 1: Copy the TlsnClient
TheTlsnClient is a single TypeScript file with zero dependencies. Copy it into your project:
TlsnClient.ts (click to expand)
TlsnClient.ts (click to expand)
TlsnClient.ts
Step 2: Use in Your App
Framework Examples
Vite + TypeScript
TlsnClient.ts into src/, then use it in src/main.ts:
src/main.ts
React (Vite or CRA)
src/hooks/useTlsn.ts
src/App.tsx
Next.js
SinceTlsnClient uses document and window, it must run client-side only:
app/components/TlsnAttest.tsx
SvelteKit
src/lib/components/TlsnAttest.svelte
Vue / Nuxt
components/TlsnAttest.vue
TlsnClient API Reference
Constructor Options
| Option | Type | Default | Description |
|---|---|---|---|
iframeUrl | string | required | URL of the hosted TLSN embed |
container | HTMLElement | document.body | Element to append the hidden iframe to |
timeout | number | 300000 (5 min) | Timeout for RPC calls in ms |
readyTimeout | number | 30000 (30s) | Timeout for iframe initialization in ms |
debug | boolean | false | Log all postMessage traffic to console |
Methods
| Method | Returns | Description |
|---|---|---|
waitReady() | Promise<void> | Wait for iframe to initialize |
connect(rpcUrl) | Promise<void> | Connect to Demos Network node |
connectWallet(mnemonic) | Promise<string> | Connect wallet, returns address |
disconnect() | Promise<void> | Disconnect from network |
generateMnemonic() | Promise<string> | Generate a new BIP39 mnemonic |
getAddress() | Promise<string> | Get connected wallet address |
getBalance() | Promise<string> | Get wallet balance in DEM |
checkTlsNotary() | Promise<boolean> | Check if TLSNotary is enabled on the node |
previewTranscript(request) | Promise<TranscriptPreview> | Preview request/response before attesting |
attest(request, options?) | Promise<AttestResult> | Perform TLS attestation |
verify(presentation) | Promise<VerifyResult> | Verify a proof locally |
storeProof(tokenId, presentation) | Promise<StoreResult> | Store proof on-chain |
destroy() | void | Remove iframe, reject pending calls, clean up |
Events
Self-Hosting the TLSN Embed (Optional)
The public instance athttps://tlsn.demos.sh is the easiest way to get started. If you need to host the embed yourself (for example, on a private network or for development), you can use Docker Compose.
Prerequisites
Clone the tlsn-component repository and build:Run with Docker Compose
docker-compose.yml
http://localhost:8443. Caddy handles the required Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers automatically.
Then point your client to the local instance:
The COOP/COEP headers (
Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp) are required because TLSNotary uses SharedArrayBuffer for WASM threads. These headers are configured on the embed server, not on your app’s server. If you use the public https://tlsn.demos.sh instance, you don’t need to worry about this.Troubleshooting
“iframe did not become ready within 30000ms”- Verify the iframe URL is reachable: open
https://tlsn.demos.shdirectly in a browser tab - Check your browser’s console for CORS or CSP errors
- If self-hosting, ensure COOP/COEP headers are being served
- Attestation can take 2-5 seconds. The default timeout is 5 minutes.
- Check network connectivity to the Demos RPC node
- Enable
debug: truein constructor options to see postMessage traffic
TlsnClientuses browser APIs (document,window). Only import and instantiate it in client-side code.- In Next.js: use
'use client'directive or dynamic imports with{ ssr: false } - In Nuxt: use
<ClientOnly>wrapper oronMounted()lifecycle hook