Framework adapters
Drop-in Next.js, Hono, Fastify, and Express handlers that proxy every DuckViz endpoint through your backend.
Adapters wire the SDK to your HTTP framework so the browser never holds the API token. Any request your frontend makes to /api/duckviz/* is forwarded to DuckViz Cloud with the token attached server-side.
All four adapters share the same proxy core, so the security posture is identical: server-side bearer injection, SSE pass-through without buffering, response-header whitelist (no Set-Cookie or CORS headers from upstream are forwarded), and AbortSignal propagation in both directions.
Pick the one that matches your stack.
import { createDuckvizHandlers } from "@duckviz/sdk/next";
export const { POST, GET } = createDuckvizHandlers({
token: process.env.DUCKVIZ_TOKEN!,
});createDuckvizHandlers returns an object with POST and GET route handlers, both pointing at the same internal proxy function. Mount as a catch-all route.
import { Hono } from "hono";
import { createDuckvizHonoHandler } from "@duckviz/sdk/hono";
const app = new Hono();
app.all(
"/api/duckviz/*",
createDuckvizHonoHandler({ token: process.env.DUCKVIZ_TOKEN! }),
);
export default app;The default prefix is /api/duckviz. Pass prefix if you mount at a different path:
app.all("/v1/duckviz/*", createDuckvizHonoHandler({
token: process.env.DUCKVIZ_TOKEN!,
prefix: "/v1/duckviz",
}));import Fastify from "fastify";
import { duckvizFastifyPlugin } from "@duckviz/sdk/fastify";
const fastify = Fastify();
await fastify.register(duckvizFastifyPlugin, {
prefix: "/api/duckviz",
token: process.env.DUCKVIZ_TOKEN!,
});
await fastify.listen({ port: 3000 });Compatible with Fastify v4 and v5. The plugin reads its mount prefix from fastify.prefix, so the prefix you pass to register() is the one source of truth — no duplication.
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_TOKEN! }),
);
app.listen(3000);Compatible with Express v4 and v5. Mount via app.use(prefix, middleware) — Express strips the prefix from req.url automatically. Mounting via app.all("/api/duckviz/*", ...) is not supported and produces wrong upstream paths.
The handler auto-proxies every SDK-targeted endpoint: /api/widget-flow/*, /api/detect-log-format, /api/generate-report-sections, /api/modify-report-section, /api/generate-deck-slides, /api/credits/balance, /api/usage, and more. SSE streams are forwarded transparently.
Token
Mint a personal access token at app.duckviz.com/settings/tokens. Store it as DUCKVIZ_TOKEN in your server environment — never inline it in client code.
Access control
Every adapter accepts an onRequest hook fired before each upstream call. Return false to reject the request with a 403 — useful for per-tenant authorization, feature gating, or rate limiting upstream of the proxy:
import { createDuckvizHandlers } from "@duckviz/sdk/next";
import { getServerSession } from "next-auth";
export const { POST, GET } = createDuckvizHandlers({
token: process.env.DUCKVIZ_TOKEN!,
onRequest: async ({ request }) => {
const session = await getServerSession();
return Boolean(session); // false → 403
},
});The onRequest option exists on every adapter (createDuckvizHonoHandler, duckvizFastifyPlugin, duckvizExpressMiddleware) with the same signature.
Configuring the frontend
Point the DuckViz components' customFetch at your proxy. Same shape works for <Explorer>, <ReportBuilder>, and <DeckBuilder>:
export const customFetch: typeof fetch = (input, init) => {
const url = typeof input === "string" ? input : input.url;
const proxied = url.replace(/^\/api\//, "/api/duckviz/");
return fetch(proxied, {
...init,
credentials: "include",
});
};<Explorer customFetch={customFetch} authenticated={true} /* ... */ />Other backends
Not on Node? The proxy is just authenticated request forwarding. Three rules in any language:
- Attach
Authorization: Bearer ${process.env.DUCKVIZ_TOKEN}server-side. - Don't buffer SSE responses — stream them straight through.
- Never log the token.
First-party SDKs for non-Node stacks are on the roadmap.
See Server Proxy Setup for additional patterns: rate limiting, logging, and per-tenant token rotation.