DuckVizBeta
Guides

Server Proxy Setup

Proxy DuckViz AI calls through your backend with @duckviz/sdk.

When you use DuckViz packages in your own app, AI features (widget recommendations, report generation, log detection) need to call DuckViz API endpoints. The @duckviz/sdk package lets you proxy these calls through your own backend, so you can control authentication, rate limiting, and access.

Scaffolding from scratch?

npx duckviz create-app my-app ships this proxy + the customFetch rewrite already wired into Explorer / Report / Deck. The rest of this guide is for adding the same plumbing to an existing Next.js / Hono / Fastify / Express app.

Why use a proxy?

  1. Token security — your DuckViz API token stays on the server, never exposed to the client
  2. Access control — add your own auth checks before forwarding requests
  3. Path flexibility — mount the proxy at any path in your API
  4. Request logging — log and monitor DuckViz API usage

Getting a token

  1. Go to app.duckviz.com/settings/tokens
  2. Click Create Token
  3. Copy the token (format: dvz_live_...)
  4. Store it as a server-side environment variable
# .env.local (or your server env)
DUCKVIZ_API_TOKEN=dvz_live_abc123...

Next.js setup

1. Create the proxy route

Use createDuckvizHandlers from @duckviz/sdk/next:

// app/api/duckviz/[...route]/route.ts
import { createDuckvizHandlers } from "@duckviz/sdk/next";

const handler = createDuckvizHandlers({
  token: process.env.DUCKVIZ_API_TOKEN!,
});

export const GET = handler;
export const POST = handler;

This creates a catch-all route that forwards requests to DuckViz:

  • POST /api/duckviz/widget-flow/fast-recommend → DuckViz widget generation
  • POST /api/duckviz/widget-flow/classify → domain classification
  • POST /api/duckviz/detect-log-format → log format detection
  • etc.

2. Configure the Explorer

Pass a customFetch function that rewrites API paths to your proxy:

const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {
  if (typeof input === "string" && input.startsWith("/api/")) {
    input = input.replace(/^\/api\//, "/api/duckviz/");
  }
  return fetch(input, init);
};

<Explorer
  customFetch={customFetch}
  authenticated={true}
  // ... other props
/>

The Explorer internally calls /api/widget-flow/fast-recommend. The customFetch rewrites this to /api/duckviz/widget-flow/fast-recommend, which hits your proxy route.

How SSE pass-through works

Several DuckViz API endpoints use Server-Sent Events (SSE) for streaming responses (widget generation, report sections). The SDK proxy handles this transparently:

  1. Client sends a POST request
  2. Your proxy forwards it to DuckViz with the bearer token
  3. DuckViz responds with text/event-stream
  4. The proxy streams the response body back to the client

The customFetch on the client handles the SSE parsing via @duckviz/shared's apiSSE helper.

Adding access control

You can add your own authentication before the proxy forwards requests. Wrap the handler:

// app/api/duckviz/[...route]/route.ts
import { createDuckvizHandlers } from "@duckviz/sdk/next";
import { NextRequest, NextResponse } from "next/server";

const duckvizHandler = createDuckvizHandlers({
  token: process.env.DUCKVIZ_API_TOKEN!,
});

async function withAuth(req: NextRequest) {
  // Add your own auth check
  const session = await getServerSession(req);
  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  // Forward to DuckViz
  return duckvizHandler(req);
}

export const GET = withAuth;
export const POST = withAuth;

Express setup

For Express backends, use the middleware adapter:

import express from "express";
import { duckvizExpressMiddleware } from "@duckviz/sdk/express";

const app = express();
app.use(express.json()); // required for body forwarding

app.use(
  "/api/duckviz",
  duckvizExpressMiddleware({
    token: process.env.DUCKVIZ_API_TOKEN!,
  }),
);

app.listen(3000);

Error handling

The proxy forwards DuckViz error responses to the client:

StatusErrorMeaning
401DuckvizAuthErrorInvalid or expired token
402DuckvizQuotaExceededErrorNo credits remaining
429DuckvizRateLimitErrorToo many requests
5xxDuckvizServerErrorDuckViz server error

The Explorer handles these errors gracefully — showing appropriate messages to the user.