Skip to Content

Quick start — first matched ad

From install to a matched ad on screen in six steps.

Use this guide when you already have a React or Next.js app and want Adzen to deliver a contextual ad alongside some content — an assistant message, an article, a search result, anything with text to match against.

This is the generic path: no CopilotKit, no AG-UI. If you’re on CopilotKit/AG-UI agents, see the CopilotKit quick start.

Prerequisites

  • React >=18
  • A place to run server code with access to your API key (a Next.js route handler / server action, or any Node >=18 backend)
  • An Adzen API key

Step 1: Install

npm install @adzenai/ai @adzenai/core

Or with pnpm:

pnpm add @adzenai/ai @adzenai/core

Step 2: Configure your environment

Put your key somewhere only the server can read it:

ADZEN_API_KEY=your_api_key

Step 3: Fetch a placement on the server

fetchAdzenAd sends your key as the X-API-Key header, so it must run server-side. It returns an AdzenPlacement, or null when there is no match (it never throws).

// app/api/ad/route.ts (Next.js App Router) import { fetchAdzenAd } from "@adzenai/ai"; export async function POST(req: Request) { const { content } = await req.json(); const placement = await fetchAdzenAd({ apiKey: process.env.ADZEN_API_KEY!, content, // the text to match an ad against messageId: crypto.randomUUID(), // any stable id for this placement location: process.env.ADZEN_LOCATION, // optional geo-targeting }); return Response.json({ placement }); }

You can also call fetchAdzenAd directly inside a server action or a React Server Component — anywhere that runs on the server.

Keep the key server-side. Calling fetchAdzenAd from a browser (client component) would ship your API key in the bundle. Always fetch on the server and pass only the returned AdzenPlacement to the client.

Step 4: Render the ad

<AdzenCard> is a client component ("use client"). Pass it the placement your server returned. It renders null when ad is null, so it’s safe to render unconditionally.

"use client"; import { useEffect, useState } from "react"; import { AdzenCard } from "@adzenai/ai/react"; import type { AdzenPlacement } from "@adzenai/ai"; export function SponsoredSlot({ content }: { content: string }) { const [ad, setAd] = useState<AdzenPlacement | null>(null); useEffect(() => { fetch("/api/ad", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content }), }) .then((r) => r.json()) .then((d) => setAd(d.placement)) .catch(() => {}); }, [content]); // AdzenCard's `ad` prop doesn't accept null, so render it only once there's a placement. return ad ? <AdzenCard ad={ad} /> : null; }

AdzenCard fires the render and view impression beacons for you — no extra wiring needed.

Step 5 (optional): Render your own markup

Your product, your design language. To use your own layout while keeping impression tracking, use useAdImpressions. It returns a ref to attach to your ad element; the render beacon fires on mount and the view beacon fires once the element has been visible long enough.

"use client"; import { useAdImpressions } from "@adzenai/ai/react"; import type { AdzenPlacement } from "@adzenai/ai"; export function CustomAd({ ad }: { ad: AdzenPlacement | null }) { const { ref } = useAdImpressions(ad); if (!ad) return null; return ( <aside ref={ref} className="my-ad"> <span className="label">Sponsored · {ad.advertiser_name}</span> <a href={ad.destination_url} target="_blank" rel="noopener sponsored"> {ad.headline} — {ad.cta_text} </a> </aside> ); }

Step 6: Verify

  1. Trigger a fetch (send a message, load an article, etc.).
  2. Confirm the placement appears when Adzen returns a match, and nothing renders when it doesn’t.
  3. In the Network tab, confirm a GET to the render impression URL fires when the ad mounts.
  4. Keep the ad on screen for ~1 second (default viewability threshold) and confirm the view impression GET fires.
  5. Your Adzen contact can confirm the impression events were recorded.

Next

Last updated on