Bolt Integration
Add health widgets to your Bolt app in three steps. This guide walks through setting up the BioUI Web SDK inside a Bolt (bolt.new) project using a Next.js API route for secure token-based authentication.
Prerequisites
- An AnyBio account with a project key (
proj_*) and a Write-scoped API key (org_*) - A Bolt project using the Next.js template (recommended) or any framework that supports server-side routes
Architecture
Bolt App (Next.js in StackBlitz WebContainer)
│
│ 1. User interacts with your app
│
│ 2. App calls Next.js API route
│ POST /api/anybio-auth
│
│ 3. API route calls AnyBio (server-side, secret key)
│ POST https://api.anybio.io/api/v1/sdk/token
│ Authorization: Bearer org_your_write_key
│
│ 4. AnyBio returns short-lived JWT (1 hour)
│ { xuser_token: "eyJ...", xuser_id: "...", expires_in: 3600 }
│
│ 5. App passes token to <bio-provider>
│ <bio-provider sdk-key="sdk_..." xuser-token="eyJ...">
│
│ 6. Widgets make API calls using the JWT
│ Authorization: Bearer eyJ...Your Write-scoped API key never leaves the server. The browser only sees a short-lived, user-scoped JWT.
Step 1: Create the API Route
In your Bolt project, create a Next.js API route that mints AnyBio xuser tokens.
Create the file app/api/anybio-auth/route.ts:
import { NextRequest, NextResponse } from "next/server";
const ANYBIO_API_KEY = process.env.ANYBIO_API_KEY!;
const ANYBIO_PROJECT_KEY = process.env.ANYBIO_PROJECT_KEY!;
export async function POST(request: NextRequest) {
// In production, verify the caller is authenticated with your app's auth.
// For prototyping in Bolt, you can use a simple user ID.
const { userId } = await request.json();
if (!userId) {
return NextResponse.json({ error: "Missing userId" }, { status: 400 });
}
const res = await fetch("https://api.anybio.io/api/v1/sdk/token", {
method: "POST",
headers: {
Authorization: `Bearer ${ANYBIO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
external_id: userId,
project_key: ANYBIO_PROJECT_KEY,
}),
});
if (!res.ok) {
const body = await res.text();
return NextResponse.json(
{ error: `AnyBio error: ${body}` },
{ status: 502 }
);
}
const data = await res.json();
return NextResponse.json(data);
}Then add your secrets to the Bolt project's .env.local:
ANYBIO_API_KEY=org_your_write_key_here
ANYBIO_PROJECT_KEY=proj_your_project_key_hereBolt tip: In Bolt's StackBlitz environment, create
.env.localvia the file explorer. Environment variables prefixed withNEXT_PUBLIC_are exposed to the browser — your API key does NOT have that prefix, so it stays server-side.
Step 2: Add the SDK to Your App
In your Bolt project's root layout or app/layout.tsx, add the BioUI Web SDK:
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.anybio.io/biosdk-web/v1/bioui-base.css" />
</head>
<body>
{children}
<Script src="https://cdn.anybio.io/biosdk-web/v1/bioui.js" strategy="afterInteractive" />
</body>
</html>
);
}Then add the provider and widgets to a page component:
"use client";
export default function Dashboard() {
return (
<bio-provider
id="bio"
sdk-key="sdk_your_key"
base-url="https://api.anybio.io"
>
<bio-health-metrics></bio-health-metrics>
<bio-mood></bio-mood>
<bio-checkin question-types='["readiness","confidence","worry"]'></bio-checkin>
</bio-provider>
);
}Note: BioUI Web uses custom elements (Web Components). In Next.js, you need the
"use client"directive on any page that renders them — custom elements require browser APIs.
The widgets won't render data until a valid xuser-token is set on the provider.
Step 3: Initialize After Login
After your user authenticates (or on page load for prototyping), call the API route to get a token and pass it to the provider:
"use client";
import { useEffect } from "react";
export default function Dashboard() {
useEffect(() => {
async function initBio() {
const res = await fetch("/api/anybio-auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "demo-user-1" }),
});
if (!res.ok) {
console.error("Failed to get AnyBio token");
return;
}
const { xuser_token } = await res.json();
const provider = document.getElementById("bio");
provider?.setAttribute("xuser-token", xuser_token);
}
initBio();
}, []);
return (
<bio-provider
id="bio"
sdk-key="sdk_your_key"
base-url="https://api.anybio.io"
>
<bio-health-metrics></bio-health-metrics>
<bio-mood></bio-mood>
</bio-provider>
);
}Token Refresh
Tokens expire after 1 hour. Listen for the expiry warning and refresh automatically:
useEffect(() => {
function handleExpiring() {
fetch("/api/anybio-auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "demo-user-1" }),
})
.then((res) => res.json())
.then(({ xuser_token }) => {
document.getElementById("bio")?.setAttribute("xuser-token", xuser_token);
});
}
document.addEventListener("anybio:token:expiring", handleExpiring);
return () => document.removeEventListener("anybio:token:expiring", handleExpiring);
}, []);Working with Bolt's AI Agent
When prompting Bolt's AI to build a health app, include the integration details. Here's a prompt template:
Add AnyBio BioUI Web health widgets to my Next.js app. The SDK CDN URL is https://cdn.anybio.io/biosdk-web/v1/bioui.js and the CSS is https://cdn.anybio.io/biosdk-web/v1/bioui-base.css. Create a Next.js API route at
/api/anybio-auththat callsPOST https://api.anybio.io/api/v1/sdk/tokenwithAuthorization: Bearer ${process.env.ANYBIO_API_KEY}and body{ external_id: userId, project_key: process.env.ANYBIO_PROJECT_KEY }. Then add<bio-health-metrics>and<bio-mood>widgets inside a<bio-provider>on the dashboard page. Use"use client"for the page with widgets. Follow the guide at https://docs.anybio.io/bioui-web/guides/bolt-integration.
Available Widgets
| Widget | Tag | Purpose |
|---|---|---|
| Health Metrics | <bio-health-metrics> | Wearable data (steps, sleep, heart rate, stress) |
| Journal | <bio-journal> | Daily journaling with prompts |
| Mood | <bio-mood> | Mood tracking with configurable scales |
| Check-in | <bio-checkin> | PRO questionnaires |
| Task List | <bio-task-list> | Daily task tracking |
| Progress Ring | <bio-progress-ring> | Circular progress visualization |
| Trend Card | <bio-trend-card> | Single biosignal trend summary |
| Trend Chart | <bio-trend-chart> | Multi-biosignal trend charts |
Non-Next.js Templates
If your Bolt project uses React + Vite or plain HTML instead of Next.js, you won't have API routes for server-side token minting. In that case:
- Use an external serverless function (e.g., Cloudflare Workers, Vercel Edge Functions, or any backend you control) to host the token endpoint.
- Call that endpoint from your Bolt app instead of
/api/anybio-auth. - The rest of the guide (SDK setup, widgets, token refresh) is the same.
See the Authentication guide for the full server-side token flow.
Security Notes
- Your AnyBio Write-scoped API key (
org_*) stays in the API route — never exposed to the browser - The
xuser-tokenis a short-lived JWT (1-hour expiry, RS256-signed) - Each token is scoped to a single user — cross-user access is impossible
- In production, add proper auth verification to the API route before minting tokens
Troubleshooting
| Issue | Solution |
|---|---|
| Widgets show "Loading..." indefinitely | Check that xuser-token is set on the provider. Open DevTools and verify the API route returns a token. |
| API route returns 502 | Verify ANYBIO_API_KEY is set in .env.local. The key must have Write scope. |
| Custom elements not rendering | Make sure the page has "use client" directive. Custom elements require browser APIs. |
ReferenceError: document is not defined | You're rendering <bio-provider> in a Server Component. Add "use client" to the file. |
| Token expired | Listen for the anybio:token:expiring event and refresh. See Token Refresh above. |