> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upsolve.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Frontend Setup

> Set up frontend for dashboard deployment

Deploy your analytics in your frontend by embedding your application as an iFrame. An application renders the current user's space — the dashboards and charts they have access to.

Please click on the Deploy button in the Hub.

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/upsolve/hc11MEa6NXVqUb70/images/build-your-first-dashboard/light/deploy.png?fit=max&auto=format&n=hc11MEa6NXVqUb70&q=85&s=bc3511f304411702b34126baa47b1e77" alt="Hero Light" width="3840" height="2160" data-path="images/build-your-first-dashboard/light/deploy.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/upsolve/hc11MEa6NXVqUb70/images/build-your-first-dashboard/dark/deploy-dark.png?fit=max&auto=format&n=hc11MEa6NXVqUb70&q=85&s=82fc90cd2a6cd8c003e163e87a01953a" alt="Hero Dark" width="3840" height="2160" data-path="images/build-your-first-dashboard/dark/deploy-dark.png" />
</Frame>

You will need a project user token (JWT) for the current user and your application ID to render the correct space. The token is generated by following the steps in [Backend Setup](/embedded-bi/deploy-dashboards/backend-setup). The application ID is found in your application settings, or in the URL when viewing the application: `/projects/{projectId}/applications/{applicationId}`.

<Warning>
  **Important**: Changing the JWT token in the iframe `src` will cause the browser to reload the entire iframe. This happens automatically when:

  * The JWT expires and gets refreshed
  * User switches organizations
  * User permissions are updated

  Plan your token refresh strategy to minimize user disruption.
</Warning>

Below is an example of deploying the application with a JWT using [**Clerk middleware**](https://clerk.com/docs/references/nextjs/auth-middleware#use-after-auth-for-fine-grained-control):

```javascript theme={null}
"use client";
import React from "react";
import { useUser } from "@clerk/nextjs";

const Analytics: React.FC = () => {
  // Get the user information from Clerk and extract the Upsolve token from the metadata
  const { user } = useUser();
  const upsolveToken = user?.publicMetadata?.["upsolveToken"];
  const applicationId = "your-application-id"; // Replace with your application ID

  // Embed the application into your app
  return (
    <>
      {upsolveToken != null && typeof upsolveToken === "string" && (
        <iframe
          id={applicationId}
          title="Embedded Analytics"
          width="1000"
          height="1000"
          src={`https://ai-hub.upsolve.ai/share/application/${applicationId}?jwt=${upsolveToken}`}
        />
      )}
    </>
  );
};

export default Analytics;
```

### Understanding JWT Changes and Iframe Refresh

When the `upsolveToken` value changes in the code above, React will re-render the component with a new `src` URL for the iframe. **This causes the browser to completely reload the iframe content.**

```javascript theme={null}
// Example: Token change triggers iframe reload
const Analytics: React.FC = () => {
  const { user } = useUser();
  const upsolveToken = user?.publicMetadata?.["upsolveToken"];

  // When upsolveToken changes (e.g., from token refresh or user switch),
  // the iframe src changes, triggering a full browser reload of the iframe

  return (
    <iframe
      src={`https://ai-hub.upsolve.ai/share/application/${applicationId}?jwt=${upsolveToken}`}
      // ↑ Changing upsolveToken here causes iframe reload
    />
  );
};
```

**Common scenarios that trigger iframe reload:**

* Automatic token refresh (every hour)
* User switches between organizations
* User logs out and back in
* User permissions are updated

<Tip>
  To improve user experience during token updates: 1. Cache the previous token
  until just before expiration 2. Show a loading overlay during refresh 3.
  Coordinate token updates during natural breaks in user workflow
</Tip>

<AccordionGroup>
  <Accordion title="Database Row-Level Security (RLS) Setup">
    For databases with Row-Level Security policies (Postgres, Redshift, or Supabase), you need to include a database auth token (`dbAuthToken`) in the iFrame `src` URL. This token identifies the current user and is used by your database's RLS policies to filter data at the row level.

    Example updated iFrame URL:

    ```javascript theme={null}
    <iframe
      id="your-application-id"
      title="Embedded Analytics"
      width="1000"
      height="1000"
      src="https://ai-hub.upsolve.ai/share/application/<applicationId>?jwt=<upsolveToken>&dbAuthToken=<yourDbAuthToken>"
    />
    ```

    * **dbAuthToken**: The user-specific identifier that your RLS policies use for row-level filtering

    ### For Postgres and Redshift

    The `dbAuthToken` should contain the value that matches your RLS session variable (e.g., tenant ID, user ID, or company code):

    ```javascript theme={null}
    const Analytics: React.FC = () => {
      const { user } = useUser();
      const upsolveToken = user?.publicMetadata?.["upsolveToken"];
      const dbAuthToken = user?.publicMetadata?.["companyId"]; // Your user's company/tenant identifier

      return (
        <iframe
          src={`https://ai-hub.upsolve.ai/share/application/${applicationId}?jwt=${upsolveToken}&dbAuthToken=${dbAuthToken}`}
        />
      );
    };
    ```

    Learn more about setting up RLS for Postgres and Redshift in the [RLS & Schema Filtering guide](/embedded-bi/data-permissioning/rls-management).

    ### For Supabase

    To retrieve the Supabase session token (`dbAuthToken`), you can use Supabase's `auth.getSession` method:

    ```javascript theme={null}
    import { createClient } from '@supabase/supabase-js';

    const supabase = createClient(
      'https://your-supabase-project.supabase.co',
      'public-anon-key'
    );

    async function getDbAuthToken() {
      const {
        data: { session },
        error,
      } = await supabase.auth.getSession();

      if (error) {
        console.error('Error retrieving session:', error.message);
        return null;
      }

      return session?.access_token;
    }

    getDbAuthToken().then((dbAuthToken) => {
      console.log('dbAuthToken:', dbAuthToken);
      // Use dbAuthToken in the iframe URL
    });
    ```

    Refer to the [Supabase API docs](https://supabase.com/docs/reference/javascript/auth-getsession) for more details on managing sessions and tokens.
  </Accordion>
</AccordionGroup>

### Application Query Parameters

The application iframe supports the following query parameters:

| Parameter | Type | Required | Description |
| - | - | - | - |
| `jwt` | string | Yes | Project user token for authentication |
| `dashboardId` | string | No | Open exactly this dashboard, with the sidebar and tabs hidden. Accepts a v2 dashboard ID or a migrated v1 one. An ID the token cannot see shows "Dashboard not found." |
| `dbAuthToken` | string | No | Database authentication token for RLS (see RLS section). `supabaseToken` is accepted as an alias. |
| `hideHeader` | boolean | No | `true` hides the dashboard title. Can only hide it: a role that hides the header cannot be overridden with `false`. |
| `hideDownloadButton` | boolean | No | `true` hides the CSV download control. Same force-hide rule as `hideHeader`. |
| `parentOrigin` | string | No | Your page's origin, e.g. `https://your-app.com`. Enables two-way filter sync over `postMessage` — see [Live Filter Sync](/embedded-bi/sharing-and-export/iframe-messaging). |
| `autoHeight` | boolean | No | `true` makes the embed report its content height so you can size the iframe to it (requires `parentOrigin`) — see [Auto-height](/embedded-bi/sharing-and-export/iframe-messaging#auto-height). |
| `transparent` | boolean | No | Render with a transparent background so your page shows through |
| `filter_{key}` | JSON string | No | Controlled filter values — see [URL Filter Parameters](/embedded-bi/filters/url-filter-parameters) |
| `f_{...}` | string | No | Omnibar filter values — see [URL Filter Parameters](/embedded-bi/filters/url-filter-parameters) |

<Note>
  The application iframe has no `theme` parameter. Its colors, fonts and light/dark
  styling come from the application's theme, which you set in the Hub; every
  embed of the application uses it. (The AI chat embed below does accept `theme`.)
</Note>

To embed one dashboard when you only have its ID (for example, the ID you passed
to `<UpsolveDashboard />`), use `/share/dashboard/{dashboardId}?jwt=…`. It looks up
the dashboard's application and opens it as above, keeping every other
parameter. See [Migrate from v1 to v2](/api-reference/v2/migrate-from-v1).

***

## Deploying AI Chat

Deploy AI chat in your frontend by embedding it as an iFrame.

You'll need a project user token (JWT) for the current user and the workspace ID to render the chat interface. The token is generated by following the steps in [Backend Setup](/embedded-bi/deploy-dashboards/backend-setup).

### Getting the workspace ID

You can find your workspace ID in the workspace URL — `/projects/{projectId}/workspaces/{workspaceId}` — or in the embed snippet on the workspace's **Deploy** page, which builds the iframe for you.

<Frame>
  <img src="https://mintcdn.com/upsolve/AQuHHtApbrMXROxw/images/ai-agent-builder/workspaces/workspace-deploy.png?fit=max&auto=format&n=AQuHHtApbrMXROxw&q=85&s=bf4b4166a08dfc958b2b64996ac2affb" alt="A workspace's Deploy page with the embed code and preview link generator" width="1600" height="1000" data-path="images/ai-agent-builder/workspaces/workspace-deploy.png" />
</Frame>

<Note>
  **Authentication via JWT**: Chat iframes use JWT tokens passed via query
  parameters for authentication, similar to applications. Users don't need to be
  logged into the Hub - they just need a valid JWT token in the URL.
</Note>

<Warning>
  **Important**: Changing the JWT token in the iframe `src` will cause the browser to reload the entire iframe and **reset the chat session**. This happens automatically when:

  * The JWT expires and gets refreshed
  * User switches organizations
  * User permissions are updated

  Each iframe load starts a fresh chat session. Plan your token refresh strategy carefully to avoid interrupting active conversations.
</Warning>

Below is an example of deploying chat with JWT using [**Clerk middleware**](https://clerk.com/docs/references/nextjs/auth-middleware#use-after-auth-for-fine-grained-control):

```javascript theme={null}
"use client";
import React from "react";
import { useUser } from "@clerk/nextjs";

const AIChatInterface: React.FC = () => {
  // Get the user information from Clerk and extract the Upsolve token from the metadata
  const { user } = useUser();
  const upsolveToken = user?.publicMetadata?.["upsolveToken"];
  const projectId = "your-project-id"; // Replace with your project ID
  const workspaceId = "your-workspace-id"; // Replace with your workspace ID

  // Embed the chat component into your app
  return (
    <>
      {upsolveToken != null && typeof upsolveToken === "string" && (
        <iframe
          id={workspaceId}
          title="AI Chat"
          width="100%"
          height="800"
          style={{ border: "none" }}
          src={`https://ai-hub.upsolve.ai/share/workspace/${projectId}/${workspaceId}?jwt=${upsolveToken}&theme=light`}
        />
      )}
    </>
  );
};

export default AIChatInterface;
```

### Chat Query Parameters

The chat iframe supports the following query parameters:

| Parameter | Type | Required | Description |
| - | - | - | - |
| `jwt` | string | Yes | Project user token for authentication |
| `prompt` | string | No | Initial prompt to start the conversation |
| `theme` | `light` \| `dark` | No | Visual theme |
| `isAdmin` | boolean | No | Enable admin features (default: `false`) |
| `hideHeader` | boolean | No | Hide the header UI |
| `themeConfigs` | JSON string | No | Custom theme configuration |

### Example with Initial Prompt

```javascript theme={null}
const AIChatWithPrompt: React.FC = () => {
  const { user } = useUser();
  const upsolveToken = user?.publicMetadata?.["upsolveToken"];
  const projectId = "your-project-id";
  const workspaceId = "your-workspace-id";
  const initialPrompt = "What were our top sales last quarter?";

  return (
    <iframe
      src={`https://ai-hub.upsolve.ai/share/workspace/${projectId}/${workspaceId}?jwt=${upsolveToken}&prompt=${encodeURIComponent(
        initialPrompt
      )}&theme=dark`}
      width="100%"
      height="800"
      style={{ border: "none" }}
    />
  );
};
```

### Admin Mode

Workspace embeds (`/share/workspace/...`) always render the end-user view. To inspect tool calls and traces as a builder, use the workspace's **Playground** instead.

Legacy `/share/chat/{agentId}` embeds keep working: they redirect to the workspace that replaced the agent, so they render the end-user view too.

### Understanding Session Reset on JWT Change

When the `upsolveToken` value changes, React re-renders the iframe with a new `src` URL. **This causes the browser to completely reload the iframe and start a new chat session.**

```javascript theme={null}
// Example: Token change triggers iframe reload and session reset
const AIChatInterface: React.FC = () => {
  const { user } = useUser();
  const upsolveToken = user?.publicMetadata?.["upsolveToken"];

  // When upsolveToken changes, the chat session resets
  return (
    <iframe
      src={`https://ai-hub.upsolve.ai/share/workspace/abc/def?jwt=${upsolveToken}`}
      // ↑ Changing upsolveToken resets the entire conversation
    />
  );
};
```

**Common scenarios that trigger session reset:**

* Automatic token refresh (every hour)
* User switches between organizations
* User logs out and back in
* User permissions are updated

<Tip>
  To preserve chat history across token refreshes, consider: 1. Implementing
  session persistence on your backend 2. Storing conversation history outside
  the iframe 3. Refreshing tokens during natural conversation breaks 4. Warning
  users before token expiration
</Tip>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.