Skip to content
ZHIVEXDocs

Integrate with Next.js and React

Keep the provider and Runner on the server, then stream normalized UI events to a browser-safe chat client.

TypeScriptStable
Source baseline · reviewed Aug 20, 2026

The browser package never runs providers or tools. A React client sends user input to your route; the route owns identity, credentials, policy, tool execution, and durable sessions.

Install

bun add @zhivex-ai/react @zhivex-ai/sdk @zhivex-ai/openai react react-dom

Create the server route

In app/api/chat/route.ts:

import {
  Agent,
  createPostgresSessionService,
  createRunner,
  fromUIMessage,
  toUIRunnerStreamResponse,
  type AgentApprovalResponse,
  type UIMessage
} from "@zhivex-ai/sdk";
import { createOpenAI } from "@zhivex-ai/openai";

export const runtime = "nodejs";

const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });

const runner = createRunner({
  appName: "support-chat",
  agent: new Agent({
    model: openai("gpt-4o-mini"),
    instructions: "Answer clearly and briefly."
  }),
  sessionService: createPostgresSessionService({ client: postgresClient })
});

export async function POST(request: Request) {
  const body = await request.json() as {
    message?: UIMessage;
    sessionId?: string;
    approvals?: AgentApprovalResponse[];
  };

  const userId = await resolveCurrentUserId(request);

  if (!body.message && !body.approvals?.length) {
    return Response.json({ error: "Missing message or approval." }, { status: 400 });
  }

  const stream = runner.stream({
    userId,
    sessionId: body.sessionId,
    messages: body.message ? [fromUIMessage(body.message)] : undefined,
    approvals: body.approvals,
    abortSignal: request.signal
  });

  return toUIRunnerStreamResponse(stream);
}

postgresClient and resolveCurrentUserId() belong to the application. Map the authenticated identity to the SDK call; never trust a browser-supplied user or tenant id as authorization.

Add the React client

Import the default stylesheet once from app/layout.tsx:

import "@zhivex-ai/react/styles.css";

Then create a client component:

"use client";

import { ZhivexChat, useZhivexChat } from "@zhivex-ai/react";

export function SupportChat() {
  const chat = useZhivexChat({ endpoint: "/api/chat" });

  return (
    <ZhivexChat
      controller={chat}
      header={<strong>Support assistant</strong>}
      starterPrompts={[
        "Summarize the latest updates",
        "Help me plan a rollout"
      ]}
    />
  );
}

The default transport sends the latest user message, current session id, and approval decisions. Runner + SessionService remains the source of truth for durable history.

Configure the React 0.3 experience

The ready-made chat now consumes the controller’s run activity, multimodal send API, status, copy, and optional retry capabilities. It also supports explicit themes and compact density without replacing the default stylesheet:

<ZhivexChat
  controller={chat}
  density="compact"
  theme="dark"
  formatError={() => "The assistant could not complete this request."}
  composerProps={{
    accept: "image/*,application/pdf",
    maxAttachments: 3,
    maxAttachmentBytes: 2 * 1024 * 1024
  }}
  messageListProps={{
    approvalCardProps: {
      reasonRequired: true,
      description: "This action sends data outside the current workspace."
    }
  }}
/>
  • Attachments can be selected, pasted, or dropped; keep count and byte limits narrow or upload larger files through an application-owned flow.
  • Transport and server details are hidden from users by default. Return only reviewed text from formatError; reserve showErrorDetails for trusted diagnostics.
  • theme accepts system, light, or dark; every primitive exposes a stable data-slot for application-owned styling.
  • Retry remains opt-in because replay can duplicate durable history. Enable it only when the endpoint implements idempotent regeneration.

React 0.3 changes the ready-made visual system. Recheck screenshots, CSS-variable overrides, focus behavior, compact layouts, and mobile attachment flows before rollout.

Production checklist

  • authenticate and rate-limit before provider work;
  • use Postgres instead of local files on serverless infrastructure;
  • validate request sizes and tool inputs;
  • pass request.signal into the runner and downstream I/O;
  • redact sensitive payloads before trace export;
  • apply a narrow allowlist before rendering remote media.

See observability and evaluations and the production guide before exposing the route to real users.

Zhivex AI SDKsPortable by default. Native when needed.
Copied