@querri-inc/embed

Embed Querri views in your application. Core SDK + React, Vue, Svelte, and Angular components.
3,622
Install
npm install @querri-inc/embed
Latest Version:1.0.0
Vue:3
License:MIT
Last Updated:Oct 22, 2026
Links: GitHub  ·  npm
Maintainer: querri

@querri-inc/embed

Embed Querri analytics in your app. Zero dependencies. Works everywhere.

React | Vue | Svelte | Angular | Vanilla JS | CDN

Querri Embed

Querri Embed drops a full analytics experience into your app — dashboards, reports, and data exploration — with built-in authentication, per-user access control, UI customization, and theming. One component, one server endpoint, zero dependencies.

Get Started in 60 Seconds

1. Install

npm install @querri-inc/embed

2. Add the embed

import { QuerriEmbed } from '@querri-inc/embed/react';

<QuerriEmbed
  style={{ width: '100%', height: '600px' }}
  serverUrl="https://app.querri.com"
  auth={{ sessionEndpoint: '/api/querri-session' }}
/>

Using Vue, Svelte, Angular, or Vanilla JS? See Framework Examples below.

The auth prop supports multiple modes: server tokens, share keys, and popup login. See Authentication Modes for all options.

3. Create a session endpoint

Only needed for server-token auth (sessionEndpoint or fetchSessionToken). Skip this step if using Share Key or Popup Login.

// app/api/querri-session/route.ts
import { createSessionHandler } from '@querri-inc/embed/server/nextjs';

export const POST = createSessionHandler();

Set QUERRI_API_KEY and QUERRI_ORG_ID environment variables.

createSessionHandler() creates an anonymous session. To map sessions to your authenticated users, use resolveParams in the Server SDK section.

Using a different framework? See the Server SDK section for all framework handlers.

4. Done.

The embed handles auth, token caching, and cleanup automatically.

sequenceDiagram
    participant Browser
    participant Your Server
    participant Querri API

    Browser->>Your Server: POST /api/querri-session
    Your Server->>Querri API: getOrCreate user + create session
    Querri API-->>Your Server: { session_token }
    Your Server-->>Browser: { session_token }
    Browser->>Querri API: Load embed with token

Framework Examples

React

import { QuerriEmbed } from '@querri-inc/embed/react';

<QuerriEmbed
  style={{ width: '100%', height: '600px' }}
  serverUrl="https://app.querri.com"
  auth={auth}
  startView="/dashboard/uuid"
/>

Vue

<template>
  <div style="width: 100%; height: 600px">
    <QuerriEmbed server-url="https://app.querri.com" :auth="auth" start-view="/dashboard/uuid" />
  </div>
</template>
<script setup>
import { QuerriEmbed } from '@querri-inc/embed/vue';
const auth = { shareKey: 'your-share-key', org: 'your-org-id' };
</script>

Svelte

<script>
  import QuerriEmbed from '@querri-inc/embed/svelte';
  const auth = { shareKey: 'your-share-key', org: 'your-org-id' };
</script>
<div style="width: 100%; height: 600px">
  <QuerriEmbed serverUrl="https://app.querri.com" {auth} startView="/dashboard/uuid" />
</div>

Angular

import { Component } from '@angular/core';
import { QuerriEmbedComponent } from '@querri-inc/embed/angular';

@Component({
  standalone: true,
  imports: [QuerriEmbedComponent],
  template: `<div style="width: 100%; height: 600px">
    <querri-embed [serverUrl]="'https://app.querri.com'" [auth]="auth" [startView]="'/dashboard/uuid'" />
  </div>`,
})
export class DashboardComponent {
  auth = { shareKey: 'your-share-key', org: 'your-org-id' };
}

Vanilla JS

import { QuerriEmbed } from '@querri-inc/embed';

QuerriEmbed.create('#container', {
  serverUrl: 'https://app.querri.com',
  auth: { shareKey: 'your-share-key', org: 'your-org-id' },
  startView: '/dashboard/uuid',
});

CDN

<!-- The canonical script tag: served by YOUR Querri deployment, so it can never
     version-skew against the product. (This same file is the build of this
     package's core.) -->
<script src="https://app.querri.com/sdk/querri-embed.js"></script>
<script>
  QuerriEmbed.create('#container', {
    serverUrl: 'https://app.querri.com',
    auth: { shareKey: 'your-share-key', org: 'your-org-id' },
  });
</script>

Authentication Modes

Share Key (Public Embeds)

For publicly shared dashboards. No user login required.

auth: {
  shareKey: 'abc123',  // From your dashboard's share link
  org: 'org_456',      // Your organization ID
}

Server Token (Enterprise)

Your backend exchanges an API key for a session token. Point the embed at your session endpoint:

auth: {
  sessionEndpoint: '/api/querri-session',
}

The SDK POSTs to this URL and extracts session_token from the JSON response automatically (with retry).

For full control over the request, use a callback instead:

auth: {
  fetchSessionToken: async () => {
    const res = await fetch('/api/querri-session');
    const { session_token } = await res.json();
    return session_token;
  },
}

Popup Login (User Accounts)

Users authenticate via a popup window. Session tokens are cached in localStorage.

auth: 'login'

Options

Option Type Required Description
serverUrl string Yes Querri server URL, e.g. 'https://app.querri.com'. (The old '…/builder' suffix is obsolete — one URL serves everything.)
auth QuerriAuth Yes Authentication mode (see above)
startView string No Initial view path (e.g. '/dashboard/uuid', '/inbox'). Unset opens the runtime's default view (the chat launcher).
chrome QuerriChromeConfig No UI chrome config — the v2 vocabulary (rail, header, chat, global, library, projects, dashboard, xls, print, settings), ~180 keys, typed from the runtime's own schema. See {serverUrl}/sdk/README.md for the full per-key table, or {serverUrl}/sdk/chrome-schema.json for the machine-readable schema. Legacy v1 keys (sidebar.*, chat.connectData, …) are still accepted — the runtime translates them one-way; unknown keys are dropped and reported via the config event.
theme QuerriThemeConfig No { name?: '' | 'querri' | 'querri-dark' | 'night', colors?, radius?, fontFamily? }. colors keys must be --ui-* tokens (allow-listed by the runtime). The old scheme key is dead — use name.
privacy QuerriPrivacyConfig No { sessionReplay?, identify?, errorReporting? } — analytics consent for your end-users (replay and identify default off).
locale string No Language override, e.g. 'en', 'es'.
autoHeight boolean No Grow the iframe to the embed's reported height (resize events).
readyTimeout number No Ms to wait for the iframe before warning (default 30000, 0 disables). The warning is recoverable: true and is retracted via the recovered event if the embed arrives late. timeout is a deprecated alias.

Gotchas worth knowing:

  • Legacy chrome.chat.connectData maps to a rail item now — it does nothing unless the rail is shown (chrome: { rail: { show: true } } or legacy sidebar.show: true).
  • Legacy chrome.header.{viewModeToggle,share,print,automate,settings,menu} default false in v2 (the old docs said true) and only reach share-key embeds' legacy chat page.
  • Legacy chat.skills and theme.scheme are dropped — the runtime reports the former in the config event's changes.dropped; use theme.name for the latter.
  • updateConfig() replaces the config (not a merge): send the whole object each time so keys returned to defaults actually reset.

Listen to the config event to see what the runtime did with your config:

querri.on('config', function (report) {
  // report.changes.dropped — keys the runtime doesn't know
  // report.changes.coupled — keys it turned off because a parent is off
  // report.changes.upgraded — legacy keys translated to v2
  console.log('applied at schema v' + report.schemaVersion, report.changes);
});

Events

Event Payload Description
ready {} Embed authenticated and ready
error { code, message } An error occurred
session-expired {} Session token expired
navigation { type, path?, ... } User navigated within the embed
// Example: handling events
instance.on('error', ({ code, message }) => {
  console.error(`Querri error [${code}]: ${message}`);
});

instance.on('navigation', ({ type, path }) => {
  console.log('Navigated to:', path);
});

Error Codes

Code Meaning
invalid_auth Auth config is invalid
token_fetch_failed fetchSessionToken callback failed after 3 automatic retries
popup_blocked Browser blocked the login popup
auth_failed Authentication failed after popup login
auth_required Auth required but no login mode configured
timeout Iframe didn't respond within timeout period (default: 15s, configurable via timeout option)
send_prompt_failed sendPrompt() failed — embed not ready, text empty, or current view has no prompt input

Instance API

const querri = QuerriEmbed.create('#container', options);

querri.on('ready', callback);     // Subscribe to event (chainable)
querri.off('ready', callback);    // Unsubscribe (chainable)
querri.sendPrompt(text, options); // Set or submit text in the chat prompt
querri.destroy();                 // Clean up iframe and listeners

querri.ready;    // boolean -- true when authenticated
querri.iframe;   // HTMLIFrameElement | null

QuerriEmbed.version;  // SDK version string (e.g. '0.1.0')

sendPrompt(text, options?)

Programmatically set text in the embedded chat prompt, or submit it directly.

// Place text in the prompt panel for the user to review and send
querri.sendPrompt('What were my sales last quarter?');

// Submit immediately without displaying in the prompt panel
querri.sendPrompt('What were my sales last quarter?', { autoSubmit: true });
Option Type Default Description
autoSubmit boolean false If true, submit the prompt immediately without showing it in the input

Requires ready to be true. Emits an error event with code send_prompt_failed if the embed is not ready, the text is empty, or the current view has no prompt input.

Framework Component API

React

The React component accepts all SDK options as props, plus:

Prop Type Description
className string CSS class for the container div
style CSSProperties Inline styles for the container div
onReady () => void Ready callback
onError (err) => void Error callback
onSessionExpired () => void Session expired callback
onNavigation (data) => void Navigation callback

Access the underlying instance via ref:

import { useRef } from 'react';
import { QuerriEmbed, type QuerriEmbedRef } from '@querri-inc/embed/react';

const ref = useRef<QuerriEmbedRef>(null);
// ref.current.instance -- SDK instance
// ref.current.iframe -- iframe element
<QuerriEmbed ref={ref} ... />

Vue

Events: @ready, @error, @session-expired, @navigation

Access the underlying instance via template ref:

<QuerriEmbed ref="embedRef" ... />
<!-- embedRef.instance / embedRef.iframe -->

Svelte

Events: on:ready, on:error, on:session-expired, on:navigation

Access the underlying instance via bind:this:

<QuerriEmbed bind:this={embed} ... />
<!-- embed.getInstance() / embed.getIframe() -->

Angular

Inputs: serverUrl, auth, startView, chrome, theme

Events: (ready), (error), (sessionExpired), (navigation)

Access the underlying instance via a template ref or ViewChild:

@ViewChild(QuerriEmbedComponent) embed!: QuerriEmbedComponent;
// embed.sdkInstance -- SDK instance
// embed.iframe -- iframe element

Server SDK

The server SDK is included in @querri-inc/embed -- no extra package required. Use it to create embed session tokens, manage users, enforce access policies, and interact with the full Querri API from your backend. Most apps only need a one-liner session handler.

Quick Start

Import createSessionHandler from your framework's sub-path and export a route handler:

// Next.js -- app/api/querri-session/route.ts
import { createSessionHandler } from '@querri-inc/embed/server/nextjs';
export const POST = createSessionHandler();

// SvelteKit -- src/routes/api/querri-session/+server.ts
import { createSessionHandler } from '@querri-inc/embed/server/sveltekit';
export const POST = createSessionHandler();

// React Router v7 -- app/routes/api.querri-session.ts
import { createSessionHandler } from '@querri-inc/embed/server/react-router';
export const action = createSessionHandler();

// Nuxt -- server/api/querri-session.post.ts
import { createSessionHandler } from '@querri-inc/embed/server/nuxt';
export default createSessionHandler();

// Express -- server.ts
import { createSessionHandler } from '@querri-inc/embed/server/express';
app.post('/api/querri-session', createSessionHandler());

Pass a resolveParams callback to extract user identity from your auth system instead of reading the request body directly:

// Next.js -- app/api/querri-session/route.ts
import { createSessionHandler } from '@querri-inc/embed/server/nextjs';
import { getServerSession } from 'next-auth';

export const POST = createSessionHandler({
  resolveParams: async (req) => {
    const session = await getServerSession();
    return {
      user: { external_id: session!.user!.id, email: session!.user!.email! },
      access: { sources: ['src_sales'], filters: { tenant_id: session!.user!.orgId } },
    };
  },
});

If you omit resolveParams, the handler creates an anonymous session.

Security: Always derive user identity and access from your server-side auth system. Never read user or access from the request body — a malicious client can impersonate any user or escalate access.

Environment Variables

Variable Description Default
QUERRI_API_KEY API key (qk_* format) --
QUERRI_ORG_ID Organization / tenant ID --
QUERRI_URL API host URL https://app.querri.com

Manual Setup

For custom servers or advanced use cases where you need the full Querri client API:

import { Querri } from '@querri-inc/embed/server';

const client = new Querri('qk_your_api_key');

const { session_token, expires_in } = await client.getSession({
  user: {
    external_id: 'usr_alice',
    email: 'alice@example.com',
  },
  access: {
    sources: ['src_sales'],
    filters: { tenant_id: 'acme' },
  },
  ttl: 3600,
  origin: 'https://myapp.com',
});

Per-User Filtering

Pass user_id to get FGA-filtered results for a specific user:

// List only projects the user has access to
const projects = await client.projects.list({ user_id: 'ext_alice' });

For a full user-scoped client (multiple operations with session auth), use asUser():

const session = await client.getSession({ user: 'ext_alice' });
const userClient = client.asUser(session);

const projects = await userClient.projects.list(); // FGA-filtered

Available Resources

The client exposes these resource namespaces: users, embed, policies, projects, chats, dashboards, data, files, sources, keys, sharing, audit, usage.

Full Reference

See docs/server-sdk.md for complete API documentation, including every method signature, pagination, streaming, error handling, and detailed framework integration guides.

For raw HTTP integration without the SDK, see docs/api-guide.md.

Troubleshooting

Embed is blank or has zero height

Your container needs explicit dimensions. Add style="width: 100%; height: 600px" to the container element.

"Missing API key" error

Set the QUERRI_API_KEY environment variable. Find your API key at https://app.querri.com/settings/api-keys.

timeout -- iframe didn't respond

Check that serverUrl is correct and the Querri server is reachable. The default budget is 30 seconds (measured: ~25s on Fast 3G — the whole app boots inside that window), the error carries recoverable: true, and if the embed arrives late the SDK emits recovered — so treat timeout as a warning, not a terminal failure:

querri.on('error', function (e) {
  if (e.code === 'timeout' && e.recoverable) showSpinnerNote('Still loading…');
});
querri.on('recovered', function () { clearSpinnerNote(); });

readyTimeout: 0 disables the warning entirely.

popup_blocked

The login popup requires a user gesture (e.g., a button click). Browsers block popups triggered without user interaction.

token_fetch_failed

Your fetchSessionToken callback (or sessionEndpoint fetch) failed after 3 automatic retries (1s, 2s backoff). Verify that your server endpoint returns { session_token: "..." } as JSON and is reachable.

send_prompt_failed

sendPrompt() could not deliver the text. Common causes:

  • The embed is not yet ready (wait for the ready event before calling sendPrompt).
  • The text argument is empty or not a string.
  • The current view has no chat prompt input (e.g., the user is viewing a dashboard instead of the chat).

TypeScript

All types are exported from every entry point:

import type {
  QuerriAuth,
  QuerriShareKeyAuth,
  QuerriTokenAuth,
  QuerriSessionEndpointAuth,
  QuerriChromeConfig,
  QuerriEmbedOptions,
  QuerriInstance,
  QuerriEventType,
  QuerriEventCallback,
  QuerriErrorEvent,
  QuerriNavigationEvent,
  SendPromptOptions,
} from '@querri-inc/embed';

// Framework wrappers re-export all core types, plus their own:
import type { QuerriEmbedProps, QuerriEmbedRef } from '@querri-inc/embed/react';

Requirements

The core SDK has zero dependencies and works in any modern browser.

Framework wrappers require:

Framework Minimum Version
React >= 17
Vue >= 3.2
Svelte >= 4
Angular >= 17

All framework dependencies are optional -- install only what you use.

Important Notes

  • React/Vue/Angular: Memoize the auth prop if it's an object. A new object reference on every render/change detection cycle will cause the iframe to be destroyed and recreated.
  • All framework wrappers automatically clean up the iframe on unmount.

License

MIT

Support policy

Versions below 1.0.0 receive security fixes only, for 6 months from the 1.0.0 release (2026-08-31). They speak the pre-v2 embed protocol; migrate with docs/MIGRATION.md.

Related Packages

@newschools/sdk

New Schools SDK - Multi-framework components and modules for integrating New Sch...

2,312
@openai-lite/chatui

Official ChatUI host SDK. Drop an assistant onto existing Vue, React, or vanilla...

0
rasedi-sdk

Universal Rasedi Payment Gateway SDK for React, Vue, Angular, React Native, and...

965

Version History

Version Released Vue License
1.0.0 >=3.2 MIT
0.2.1 >=3.2 MIT
0.2.0 >=3.2 MIT
0.1.24 >=3.2 MIT
0.1.23 >=3.2 MIT