Next.js
Use NotPixel in an App Router Node.js Route Handler, and render the serialized ad with notpixel/react in a Client Component. Provider credentials and local inference remain on the server.
Install in an existing application
The App Router integration, React components and Vercel AI SDK adapter are included
in the notpixel package. Choose local or remote ad-context processing:
# Local processing (default)
npm install notpixel
# Or remote processing
npm install notpixelLocal processing runs in your Next.js backend and sends a vector to NotPixel. Remote processing sends sanitized matching context to NotPixel and does not initialize a local model. Both use a Node.js Route Handler in this guide; the React card remains a Client Component.
For optional guided account connection and local/remote selection, run
npx notpixel@latest install inside your application. Direct package installation
does not ask questions or require CLI login. See Installation.
Complete AI chat example
The Next.js + Vercel AI SDK example includes a complete chat with streaming, cancellation, sponsored cards, visibility tracking and feedback actions. It uses Next.js 16, React 19, AI SDK 7 and Node.js 22+.
From a source checkout:
pnpm --filter notpixel... --filter @notpixel/embedding-local... install --no-frozen-lockfile
pnpm --filter notpixel build
cd examples/nextjs-ai-sdk
pnpm install --ignore-workspace
cp .env.example .env.local
pnpm devOpen http://localhost:3002. The example starts in demo mode with sample model responses. Set your publisher ID to preview real test ads without tracking or spend.
For real requests, set NOTPIXEL_DEMO=0, your NOTPIXEL_PUBLISHER_ID, OPENAI_API_KEY and optional OPENAI_MODEL. The publisher ID comes from your dashboard; no real publisher ID is embedded in the example. Its provider can be replaced with any compatible AI SDK model.
When copying the example into another application, replace the SDK source file:
dependency with the published notpixel package for its default local setup.
For remote processing, replace the route’s
client configuration as shown below. Follow the AI SDK guide
for AI SDK dependencies, version 6 conversion and matching package majors. Next.js
15 applications can use the same App Router recipe with their supported Node.js version.
Existing Next.js application without AI SDK
You can also fetch an ad independently of any chat framework:
import Ads from 'notpixel';
export const runtime = 'nodejs';
const ads = new Ads({ publisherId: process.env.NOTPIXEL_PUBLISHER_ID, cache: false });
export async function POST(request: Request) {
const { input } = await request.json();
if (typeof input !== 'string' || !input.trim()) {
return Response.json({ error: 'input is required' }, { status: 400 });
}
const ad = await ads.getAd({ input, request, placement: process.env.NOTPIXEL_PLACEMENT, signal: request.signal });
return Response.json({ ad: ad ?? null });
}The SDK reads the browser origin from the incoming request for development host detection. The placement identifies the verified property when the backend calls NotPixel without a browser request.
This route uses local processing. For remote processing, replace its import and client initialization; the POST handler and response shape stay the same:
import Ads from 'notpixel/remote';
const ads = new Ads({
publisherId: process.env.NOTPIXEL_PUBLISHER_ID,
cache: false,
});Use this same client configuration when passing ads to withNotPixelAds in a
chat Route Handler. Neither integration automatically sends text remotely when
local inference fails; the chat continues without an ad.
For local processing, keep the SDK and its transitive inference dependencies external to the Next.js server bundle:
export default {
serverExternalPackages: ['notpixel', '@notpixel/embedding-local', '@huggingface/transformers', 'onnxruntime-node'],
};With remote processing, use notpixel/remote and the same package installation. The local model is not initialized.
Render and track
'use client';
import { useMemo } from 'react';
import { AdCard, type Ad } from 'notpixel/react';
import { createTracker, isAdExpired } from 'notpixel/browser';
export function SponsoredCard({ ad }: { ad: Ad }) {
const tracker = useMemo(() => createTracker({ publisherId: ad.publisherId }), [ad.publisherId]);
if (ad.opportunityId) return <AdCard ad={ad} tracker={tracker} />;
if (isAdExpired(ad)) return null;
if (ad.testMode) return <AdCard ad={ad} />;
if (!ad.impressionId && !ad.opportunityId) return null;
return <AdCard ad={ad} tracker={tracker} />;
}In Settings → Domains & apps, register and verify the exact HTTPS hostname
of the chat, then create a placement and copy its code into NOTPIXEL_PLACEMENT.
The browser sends its own origin at confirmation. The SDK renders a pending opportunity without an active CTA, then
confirms it after at least half of the card is visible in a foreground tab for
one continuous second. Confirmation returns the impression ID and tracked link.
The browser confirmation works with ads selected by JavaScript or Python.
Keep each pending card keyed by opportunityId so it retains confirmation
state across chat updates. See Browser Tracking for custom renderers
and conversion tracking.
AdCard uses Tailwind utilities. Include the installed SDK in your Tailwind source scan; the complete example shows a Tailwind 4 configuration. Import notpixel/ai-sdk only on the server, and use import type for shared message types in client files.
Deploy to a Node.js host. Local processing also requires model download/cache support, the inference dependencies’ build scripts and enough memory for inference. Remote processing needs none of those local inference components. Preview and production credentials must be configured independently. The example does not include authentication, billing or conversation storage.