Article

Getting Started with QueryPanel: Embed Your First AI Dashboard

Install QueryPanel's React SDK, mint a tenant-scoped JWT, and embed an AI-assisted customer dashboard, with a headless Node SDK path for custom UI.

Csaba Ivancza
9 min read
tutorialgetting-startedReact SDKembedded analyticsAI dashboardsmulti-tenant SaaSNode SDK

Getting started with QueryPanel should begin with the customer experience you want to ship. For most SaaS teams, that means embedding a complete AI-assisted dashboard workspace in an existing React route, not assembling a query box, chart renderer, editor, and persistence layer separately.

Last reviewed August 10, 2026 against the current React SDK and Node SDK source.

Short answer: QueryPanel's primary product is its headful React SDK: a Notion-like dashboard workspace with an AI assistant and tenant-level customization. Connect and train a datasource in QueryPanel, mint a tenant-scoped JWT on your server, then render QuerypanelEmbedded in React. Use the headless Node SDK when you need a fully custom interface and backend-controlled zero-trust execution.

Key takeaways

  • Start headful for the fastest complete product path. The React SDK provides the dashboard workspace, editing, saved customer customizations, and AI-assisted chart workflows.
  • Mint embed tokens on your server. The private key and the authority to choose a tenant must never move into browser code.
  • Resolve tenant identity from your authenticated application session. Do not accept tenantId from a query parameter, React prop, or request body as the authorization decision.
  • Use one default dashboard as the starting point. With customization enabled, customers can create tenant-specific forks without modifying the deployed original.
  • Choose headless only when the UI or execution boundary requires it. The Node SDK lets your backend call qp.ask(...), execute through an attached database adapter, and render the result in your own interface.

What you will build

The primary quickstart has three parts:

  1. A datasource and dashboard prepared in QueryPanel.
  2. A server endpoint that mints a short-lived JWT for the authenticated tenant.
  3. A React route that renders the embedded workspace.

The request path is:

Your application remains responsible for authenticating the user and mapping that user to the correct tenant. QueryPanel verifies the signed JWT and uses its claims for the embedded analytics context.

Prerequisites

Before writing integration code:

  • create a QueryPanel workspace
  • connect a supported datasource
  • sync the schema and add the business definitions needed for your first questions
  • create or choose a dashboard to embed
  • keep your QueryPanel private key in server-only configuration
  • know how your application resolves the current tenantId

Start with one datasource, one dashboard, two test tenants, and five questions customers already ask. A narrow verified setup is more useful than exposing every table on day one.

Install the React and Node SDKs

Install the React SDK for the embedded workspace and the Node SDK for server-side JWT creation:

npm install @querypanel/react-sdk @querypanel/node-sdk

The React SDK belongs in your frontend bundle. The private key does not. The Node SDK must run in your server environment when it creates embed JWTs.

Initialize the Node SDK on your server

Create one server-side QueryPanel client:

import { QueryPanelSdkAPI } from "@querypanel/node-sdk";

export const qp = new QueryPanelSdkAPI(
  "https://api.querypanel.io",
  process.env.QUERYPANEL_PRIVATE_KEY!,
  process.env.QUERYPANEL_WORKSPACE_ID!,
);

The third constructor argument is your workspace ID. It is sent to the API as the JWT organizationId claim.

Do not prefix this module with "use client", import it into a client component, or expose QUERYPANEL_PRIVATE_KEY through a public environment variable.

Create a tenant-scoped embed-token endpoint

The endpoint below uses requireCustomerSession as a placeholder for your application's existing authentication and authorization logic:

import { qp } from "@/lib/querypanel";

export async function GET(request: Request) {
  const customer = await requireCustomerSession(request);

  const jwt = await qp.createJwt({
    tenantId: customer.tenantId,
    userId: customer.userId,
  });

  return Response.json({ jwt });
}

The important boundary is where customer.tenantId comes from. It must be derived from a trusted server session or authorization lookup. The browser may request an analytics token, but it must not choose the tenant encoded into that token.

Render the dashboard workspace in React

Fetch the token and pass it to QuerypanelEmbedded:

"use client";

import { useEffect, useState } from "react";
import { QuerypanelEmbedded } from "@querypanel/react-sdk";

export function CustomerAnalyticsPage() {
  const [jwt, setJwt] = useState<string | null>(null);

  useEffect(() => {
    fetch("/api/analytics/embed-token")
      .then((response) => {
        if (!response.ok) {
          throw new Error("Could not load analytics access");
        }
        return response.json();
      })
      .then((data) => setJwt(data.jwt));
  }, []);

  if (!jwt) {
    return <p>Loading analytics...</p>;
  }

  return (
    <QuerypanelEmbedded
      dashboardId="your-dashboard-id"
      apiBaseUrl="https://api.querypanel.io"
      jwt={jwt}
      allowCustomization
    />
  );
}

allowCustomization enables the customer customization flow. When a customer edits a deployed dashboard, QueryPanel can create a tenant-specific fork so the original remains unchanged.

The component also supports theming, dark mode, branding, loading callbacks, and customization callbacks. Add those after the authenticated route works for two test tenants.

Test the tenant boundary before styling

Create two tenants with deliberately different data, for example, Tenant A has 11 orders and Tenant B has 29. Then verify:

  1. each tenant receives a JWT minted from its authenticated server session
  2. the same dashboard shows different, correctly scoped results
  3. broad AI questions such as "show all revenue" remain tenant-scoped
  4. customer customizations do not alter the deployed dashboard or another tenant's fork
  5. logout, tenant switching, and two open tabs do not reuse the wrong token
  6. missing tenant context fails closed

Do this before you spend time on colors and layout. A polished dashboard with an unproven tenant boundary is still only a demo.

Add business context for better AI answers

Schema introspection tells QueryPanel which tables and columns exist. It does not fully explain your business.

Improve answers with:

  • annotations that explain tables, columns, and intended joins
  • glossary terms for words such as active customer, expansion, and usage
  • gold SQL examples for important questions your team already answers correctly
  • tenant-aware context for account-specific definitions or restrictions

Keep the first training set small. Validate five real questions, correct the context, and expand only when the answers are trustworthy.

When to use the headless Node SDK instead

Use the headless path when the analytics interface must be completely application-owned or when credentials and query results must remain inside your backend infrastructure.

The backend flow is:

  1. attach a database adapter
  2. sync schema metadata
  3. resolve the authenticated tenant
  4. call qp.ask(...)
  5. render the returned rows, chart, rationale, and follow-up session in your own UI

A current query call looks like:

const result = await qp.ask("Show revenue by month", {
  database: "analytics",
  tenantId: customer.tenantId,
  pipeline: "v2",
  chartType: "vizspec",
  debug: false,
});

return {
  rows: result.rows,
  chart: result.chart,
  rationale: result.rationale,
  querypanelSessionId: result.querypanelSessionId,
};

The v2 pipeline is the default. debug: false keeps rationales in customer-safe business language. Reuse querypanelSessionId for follow-up questions in the same tenant context.

The headless SDK is not the shorter route to a complete dashboard product: your team owns the input, chart presentation, editing, saved state, loading, empty states, errors, and follow-up UX. Choose it when that control is worth the additional scope.

Common setup mistakes

Putting the private key in browser code

The browser receives a signed JWT, never the signing key. If a value is available through a public frontend environment variable, it is not private.

Letting the browser choose tenantId

A React prop can help render state, but it is not an authorization boundary. Derive tenant identity on the server from the authenticated user.

Starting with the headless UI because it looks flexible

Maximum flexibility also means maximum product work. Start with QuerypanelEmbedded unless the interface itself is a differentiator or the data boundary requires backend-owned execution.

Syncing every table before defining the first use case

More schema context can create more plausible but incorrect query paths. Begin with the tables and business terms needed for a small verified question set.

Testing only a curated prompt

Broad questions, saved customizations, exports, empty results, and tenant switching reveal problems that a prepared demo prompt will not.

FAQ

What is the fastest way to get started with QueryPanel?

Prepare a datasource and dashboard, use the Node SDK on your server to mint a tenant-scoped JWT, and render QuerypanelEmbedded with the React SDK. This gives you the complete headful workspace without building dashboard management yourself.

Is QueryPanel primarily a React SDK or a Node SDK?

QueryPanel's primary product is the headful React SDK with a Notion-like dashboard workspace and AI assistant. The headless Node SDK is the secondary path for custom UI and zero-trust backend execution.

Can I use QueryPanel without exposing a database password to the browser?

Yes. Database credentials and private signing keys stay in server-side infrastructure. The headful embed receives a short-lived JWT; the headless path executes through the database adapter attached in your backend.

How does tenant identity reach the embedded dashboard?

Your backend resolves the authenticated customer and calls createJwt(...) with that tenant ID. QueryPanel's API verifies the signed token and creates the organization and tenant context from verified claims.

Do I need a data warehouse?

No. Many SaaS teams begin with Postgres or a read replica. A warehouse or ClickHouse becomes useful when governed metrics, event volume, concurrency, or analytical workload isolation requires it.

When should I choose the headless Node SDK?

Choose headless when you need a fully custom analytics interface or when query execution and result handling must remain inside your backend. Expect to own more frontend state and product behavior.

What should I read next?

Follow the React and Postgres tenant-safe tutorial for database attachment and schema sync. Review the zero-trust SDK architecture for the headless data boundary, or compare React embedding without iframes.


Start with the complete React workspace, prove the tenant boundary with two test customers, and expand the schema only after the first questions are trustworthy. When your product needs a custom interface or stricter backend execution boundary, add the headless Node SDK path deliberately.