Share & Export
React embed SDK
@digisquares/datasquares-embed-react wraps the embed iframe in a typed React
component: auto-resize, events for clicks and filter changes, host-side
controls for parameters and pages, and a server-side signer for each person’s
short-lived token, so every person sees their own rows
(Embed dashboards for each person).
npm install @digisquares/datasquares-embed-reactCopy an embed snippet from the Share dialog
Section titled “Copy an embed snippet from the Share dialog”The Embed tab of the Share dialog gives the iframe and React snippets.
Open the Embed tab of the Share dialog. Copy the iframe snippet for your site. The snippet needs a share token; Create embed token makes one. The web addresses that may show the embed are a workspace setting, listed under Allowed domains.

Switch to React for the component version of the snippet.

Drop in the component
Section titled “Drop in the component”For each person, pass getToken: a function that asks your server for the token it signed for the person
signed in to your product (below). The component calls it when the embed starts and again before the embed’s
session ends, and hands the token to the embed by postMessage at the exact DataSquares origin — never in a URL.
import { useRef } from 'react'import { DataSquaresEmbed, type DataSquaresEmbedHandle } from '@digisquares/datasquares-embed-react'
function Analytics() { const embed = useRef<DataSquaresEmbedHandle>(null)
return ( <DataSquaresEmbed ref={embed} baseUrl="https://app.datasquares.ai" // your DataSquares app URL getToken={() => fetch('/analytics-token').then((r) => r.text())} theme="dark" params={{ region: 'west' }} // p_* defaults baked into the URL onReady={({ pages }) => console.log('pages', pages)} onPointClick={({ cardId, value }) => console.log('clicked', cardId, value)} onFilterChange={(filters) => console.log('filters', filters)} /> )}A public share link embeds with its token and the content’s id instead:
<DataSquaresEmbed baseUrl="…" contentId="your-dashboard-id" token={shareToken} />. Everyone who has a share
link sees the same view.
The iframe grows to fit its content. Fix the height instead with
autoResize={false} and a height.
Control it from your app
Section titled “Control it from your app”The ref handle sends typed commands over the versioned ds:* postMessage
protocol:
embed.current?.setParams({ region: 'east' }) // wins over the URL's p_* defaultsembed.current?.setPage('page-id')embed.current?.refresh()const { pageId, params } = await embed.current!.getState()Events
Section titled “Events”| Prop | Fires when |
|---|---|
onReady |
the embed authorized and rendered (contentType, pages) |
onError |
it could not render — invalid, forbidden, network, password-required, expired (a person’s session ended and getToken gave no new token) |
onPageChange |
the visible dashboard page changed |
onPointClick |
a chart data point was clicked |
onFilterChange |
the cross-filter set changed (chart click, slicer, clear) |
Sign each person’s token on your server — never in the browser
Section titled “Sign each person’s token on your server — never in the browser”Make an embed app under Administration → Embedding: its client id, key id and secret (shown once) stay on your server. Your endpoint authenticates your user and signs a short-lived token for them with the server entry of the package, which never goes into a browser bundle:
// e.g. an Express or Next.js route handler on YOUR serverimport { signEmbedToken } from '@digisquares/datasquares-embed-react/server'
const token = await signEmbedToken({ clientId: process.env.DS_EMBED_CLIENT_ID!, keyId: process.env.DS_EMBED_KEY_ID!, secret: process.env.DS_EMBED_SECRET!, sub: currentUser.id, // your stable id for the person tenant: currentUser.accountId, // their customer account role: 'viewer_ai', // or 'viewer', without Ask AI attributes: { account: currentUser.accountId }, // one per row rule of the app content: { type: 'dashboard', id: 'your-dashboard-id' },})The token is HS256, lives five minutes by default and ten at most, and makes one session. The person’s attributes are signed into it: the viewer cannot see or change them, and the app’s row rules filter every card by them. What each claim means, and every refusal, is in Embed dashboards for each person.
createEmbedToken from version 0.1 is gone: the tokens it made with POST /api/embed-tokens were never accepted,
and that endpoint is retired.
Ask AI in an embed
Section titled “Ask AI in an embed”The floating Ask AI panel is a property of the share, not the
component: if the publisher turned it on for that share (Share dialog →
Link/Embed tab → Ask AI for viewers), it renders inside the embedded page
automatically — there’s no prop to enable or disable it from your app, and no
event fires for it beyond the ordinary iframe lifecycle. It shows the same
way whether the host uses <DataSquaresEmbed> or a plain iframe.
The agent only ever answers from that one share’s own cards, keeps its conversation on the server, is rate-limited per share, is paid for from the publisher’s workspace AI credits, and is off by default. See Ask AI on a share for what it does and its limits.
With getToken, Ask AI is the embed app’s: offered to a person whose token’s role is viewer_ai when the app
offers it, with each person’s own conversations kept for their next session, and budgets and hourly limits per
person and per tenant. See Ask AI for embedded people.
Restrict which sites may embed
Section titled “Restrict which sites may embed”In Sharing → Embed → Embed settings, list the domains allowed to render
your embeds (acme.com, *.partner.io). The embed identifies its host by the
frame’s ancestor origin and the DataSquares API refuses hosts not on the list.
An empty list allows every site; your own share links always keep working.
Two things to know as the host page:
- Don’t wrap the embed in
referrerpolicy="no-referrer"— an unidentifiable host is refused when a restriction is configured. The component pinsstrict-origin-when-cross-originon its iframe, which sends the origin and nothing more. - The restriction controls where content can be rendered. The token is still the credential — treat it like one.
Branding
Section titled “Branding”The same Embed settings panel carries a logo and toolbar defaults applied inside every embed (snippet URL parameters win when both are set); the theme and primary color come from the snippet or the dashboard. Embeds always show a small Powered by DataSquares credit — DataSquares does not offer white-labelling. Embed usage (views, chart clicks, filter changes, page switches) rolls up per share in the same panel.
Plain iframe
Section titled “Plain iframe”No React? The Share dialog’s Embed tab produces a copy-paste iframe
snippet for a share link — same tokens, same allowlist, same theming, without
the events and controls the SDK adds. For each person, put their signed token in
the address’s fragment, which a browser never sends to a server:
https://app.datasquares.ai/embed/session#token=SIGNED_TOKEN.