Skip to main content
Next.js is the recommended framework for building production Polpo apps. Use Server Components for secure API calls and Client Components for real-time UI.

Install

npm install @polpo-ai/sdk @polpo-ai/react

Environment variables

# .env.local
POLPO_API_URL=https://api.polpo.sh       # server-side only
POLPO_API_KEY=pk_live_...                 # server-side only
NEXT_PUBLIC_POLPO_API_URL=https://api.polpo.sh  # client-side (public)
Keep POLPO_API_KEY server-side only (no NEXT_PUBLIC_ prefix). Use a route handler to proxy authenticated requests.

Server-side: Route Handler

Create an API route that proxies chat completions with the API key injected server-side:
// app/api/chat/route.ts
import { PolpoClient } from "@polpo-ai/sdk";

const client = new PolpoClient({
  baseUrl: process.env.POLPO_API_URL!,
  apiKey: process.env.POLPO_API_KEY!,
});

export async function POST(req: Request) {
  const { messages, agent } = await req.json();

  const stream = client.chatCompletionsStream({ agent, messages });

  return new Response(
    new ReadableStream({
      async start(controller) {
        for await (const chunk of stream) {
          controller.enqueue(
            new TextEncoder().encode(`data: ${JSON.stringify(chunk)}\n\n`)
          );
        }
        controller.enqueue(new TextEncoder().encode("data: [DONE]\n\n"));
        controller.close();
      },
    }),
    {
      headers: {
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
      },
    }
  );
}

Server-side: Server Components

Fetch agent data directly in Server Components — no client-side API key exposure:
// app/agents/page.tsx
import { PolpoClient } from "@polpo-ai/sdk";

const client = new PolpoClient({
  baseUrl: process.env.POLPO_API_URL!,
  apiKey: process.env.POLPO_API_KEY!,
});

export default async function AgentsPage() {
  const agents = await client.getAgents();

  return (
    <div>
      <h1>Agents</h1>
      {agents.map(a => (
        <div key={a.name}>
          <h2>{a.name}</h2>
          <p>{a.role}</p>
        </div>
      ))}
    </div>
  );
}

Client-side: Real-time with PolpoProvider

For live updates, wrap client components with PolpoProvider. Inject the API key from the server via a layout:
// app/dashboard/layout.tsx (Server Component)
import { DashboardShell } from "./shell";

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  // Pass API config from server environment
  return (
    <DashboardShell
      apiUrl={process.env.NEXT_PUBLIC_POLPO_API_URL!}
    >
      {children}
    </DashboardShell>
  );
}
// app/dashboard/shell.tsx (Client Component)
"use client";

import { PolpoProvider } from "@polpo-ai/react";

export function DashboardShell({ apiUrl, children }: { apiUrl: string; children: React.ReactNode }) {
  return (
    <PolpoProvider baseUrl={apiUrl}>
      {children}
    </PolpoProvider>
  );
}
// app/dashboard/page.tsx (Client Component)
"use client";

import { useTasks } from "@polpo-ai/react";

export default function DashboardPage() {
  const { tasks, isLoading } = useTasks();

  if (isLoading) return <p>Loading tasks...</p>;

  return (
    <ul>
      {tasks.map(t => <li key={t.id}>{t.title}{t.status}</li>)}
    </ul>
  );
}

Pattern: Secure chat proxy

The recommended pattern for production chat apps:
Browser (Client Component)

    ├── POST /api/chat (your Next.js route)
    │       │
    │       └── PolpoClient.chatCompletionsStream()
    │               │ (POLPO_API_KEY injected server-side)
    │               │
    │               └── Polpo API

    └── SSE /api/events (optional, for live task updates)
This keeps the API key server-side while streaming responses to the browser.