React Integration
React has two honest Emban paths: a signed iframe helper for dashboard-level embeds, and a native component SDK for widget-level composition.
@emban/sdk stays server-side. Use @emban/embed-helper/react when you want the signed iframe plus runtime methods and events. Use @emban/react when you want native React widgets or a dashboard grid rendered without iframe.These four links are the fastest way to orient yourself before you wire anything into a React app.
/v1/embed-sessions. The browser never gets the admin key.
Browser
Embed Runtime
Understand the host-to-embed contract before you add helper methods or listeners.
Proof
Live demo
See the same signed session path, commands, and runtime events against seeded data.
Reference
API Reference
Keep endpoint payloads and browser command shapes in one place while you integrate.
1. Backend: create embed session
Your backend should create the signed tenant session and return the values your frontend path needs. The browser never gets the admin key.
// api/analytics.ts (your backend)
import { EmbanClient } from '@emban/sdk';
const adminClient = new EmbanClient({
baseUrl: 'https://emban.sidelabs.dev',
apiKey: process.env.EMBAN_ADMIN_KEY!,
});
app.get('/api/analytics/embed', async (req, res) => {
const dashboardId = process.env.EMBAN_DASHBOARD_ID!;
const session = await adminClient.createEmbedSession({
tenantId: req.user.orgId,
dashboardId,
expiresIn: 3600,
permissions: {
allowDrillDown: true,
allowedDimensions: ['model', 'endpoint'],
allowedPeriods: ['24h', '7d', '30d'],
},
});
res.json({
embed_url: session.embedUrl,
token: session.token,
dashboard_id: dashboardId,
host: 'https://emban.sidelabs.dev',
});
});
2. Path A: signed iframe helper
Use this when you want the published customer-facing dashboard and a thin browser runtime on top.
import { useEffect, useState } from 'react';
import { EmbanEmbedFrame, useEmbanEmbed } from '@emban/embed-helper/react';
function AnalyticsDashboard() {
const [embedUrl, setEmbedUrl] = useState('');
useEffect(() => {
fetch('/api/analytics/embed')
.then(r => r.json())
.then(({ embed_url }) => setEmbedUrl(embed_url));
}, []);
if (!embedUrl) return <div>Loading analytics...</div>;
return (
<EmbanEmbedFrame
embedUrl={embedUrl}
containerStyle={{ minHeight: 600 }}
onReady={event => console.log('ready', event.dashboardId)}
onFilter={event => console.log('filters', event.period, event.filters)}
onPeriodChange={event => console.log('period', event.previousPeriod, event.period)}
onSessionSwapped={event => console.log('session', event.previousEmbedUrl, event.embedUrl)}
/>
);
}
function RuntimeControls({ embedUrl }: { embedUrl: string }) {
const { containerRef, embed } = useEmbanEmbed({ embedUrl });
return (
<>
<div ref={containerRef} style={{ minHeight: 600 }} />
<button onClick={() => embed?.setFilters({ period: '7d' })}>Last 7 days</button>
<button onClick={() => embed?.reload()}>Reload</button>
</>
);
}
3. Iframe helper methods and events
| Method | Description |
|---|---|
Emban.create(options) | Mount dashboard into container |
<EmbanEmbedFrame embedUrl={url} /> | React wrapper around the browser helper |
dash.setEmbedUrl(nextSignedUrl) | Swap the signed tenant-scoped embed session without recreating the wrapper |
dash.setFilters({ period: '7d', dimensions: { model: 'gpt-4' } }) | Update period, dimension filters, and optional numeric/date ranges |
dash.setTheme({primaryColor: '#000'}) | Change theme colors |
dash.reload() | Force data refresh |
dash.on('ready', fn) | Fires when dashboard renders |
dash.on('filter', fn) | Reports the full active filter state, including period and active drill filters |
dash.on('period-change', fn) | Reports period transitions inside the embed |
dash.on('session-swapped', fn) | Reports signed session rotation when setEmbedUrl() replaces the current URL |
dash.on('drill', fn) | Reports apply/clear/detail drill actions |
dash.setEmbedUrl(nextSignedUrl) instead of tearing the wrapper down.4. Commands and events
The helper wraps a plain postMessage contract. If you want the higher-level model first, read Embed Runtime. If you inspect the live demo or build a very thin host runtime yourself, these are the payloads the browser layer uses.
// Host page -> embed runtime
{
"_emban": true,
"type": "setFilters",
"filters": { "period": "7d" }
}
{
"_emban": true,
"type": "setTheme",
"theme": {
"primaryColor": "#0f9d58",
"backgroundColor": "#f7f9f7",
"cardBackground": "#ffffff",
"cardBorder": "#d8e2d9",
"textColor": "#101513",
"mutedColor": "#5d6c63"
}
}
{
"_emban": true,
"type": "reload"
}
// Embed runtime -> host page
{
"_emban": true,
"type": "ready",
"dashboardId": "dash_123"
}
{
"_emban": true,
"type": "period-change",
"previousPeriod": "30d",
"period": "7d"
}
{
"_emban": true,
"type": "filter",
"period": "7d",
"filters": { "model": "gpt-4" },
"numericRanges": {},
"dateRanges": {}
}
{
"_emban": true,
"type": "drill",
"dimension": "endpoint",
"value": "/chat",
"action": "apply"
}
{
"_emban": true,
"type": "error",
"message": "Couldn't refresh this dashboard"
}
ready, resize, filter, period-change, drill, and error. The helper also emits session-swapped on the host side when setEmbedUrl() replaces the signed URL.5. Path B: native React components
Use this when you want native composition in your app layout instead of iframe. The native path still uses the same signed tenant token from your backend.
import { EmbanDashboard, EmbanProvider, EmbanWidget, useEmbanRuntime } from '@emban/react';
function RefreshButton() {
const runtime = useEmbanRuntime();
return <button onClick={() => runtime.refetch()}>Refresh widgets</button>;
}
function NativeAnalytics({ session }) {
return (
<EmbanProvider
host={session.host}
token={session.token}
dashboardId={session.dashboardId}
filters={{ period: '30d' }}
>
<section style={{ display: 'grid', gap: 16 }}>
<EmbanWidget
widgetId="requests_kpi"
height={180}
onDrillEvent={event => console.log(event.dimension, event.value, event.rawPoint)}
/>
<EmbanDashboard
rowHeight={72}
onDrillEvent={event => console.log(event.widgetId, event.label)}
/>
<RefreshButton />
</section>
</EmbanProvider>
);
}
@emban/embed-helper/react for the published dashboard and tenant-scoped session lifecycle. Use @emban/react when your product needs widget-level composition, native chart rendering, or provider-level runtime control.