Overview
Ads that follow the conversation, without touching it.
Adzen delivers contextual ads inside AI chat streams. It sits alongside CopilotKit as AG-UI middleware — intercepting assistant messages, matching ads, and rendering sponsored placements without modifying or blocking any content.
The matching is ours, the surface is yours. Adzen reads the turn the way a person would — see We understand the turn. Where the ad sits, how it looks and when it appears stay entirely in your product.
Not using CopilotKit or AG-UI? For a plain React/Next app, use the generic React & Next.js integration instead.
Where each piece runs
The integration has three layers:
| Layer | Role |
|---|---|
| Adzen | matches ads to assistant output and renders sponsored placements |
| CopilotKit | owns the chat UI, runtime route, and agent bridge |
| Backend agent | runs the LLM agent (LangGraph, custom AG-UI agent, etc.) |
┌──────────────────────────────────────────────────┐
│ CopilotKit Chat UI │
│ ┌────────────────────────────────────────────┐ │
│ │ Assistant message │ │
│ └────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ AdzenCard (sponsored placement) │ │
│ └────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
▲ ▲
│ AG-UI events │ adzen_placement
│ │ custom events
┌───────┴───────────────────────────┴──────────────┐
│ AdzenAsyncMiddleware │
│ buffers text → calls /process → emits placement │
└──────────────────────────────────────────────────┘
▲
│ AG-UI event stream
┌───────┴──────────────────────────────────────────┐
│ Backend Agent (LangGraph, AG-UI, etc.) │
└──────────────────────────────────────────────────┘Adzen is additive only — it never modifies, blocks, or delays the assistant text stream. Ad fetches run as a side-effect after each assistant message completes.
Before you start
- Get an Adzen API key from your Adzen account representative.
- Have a working CopilotKit app.
What the code looks like
Server-side: pipe AG-UI events through the middleware
import { AdzenAsyncMiddleware } from "@adzenai/ai/copilotkit";
const adzen = new AdzenAsyncMiddleware({
apiKey: process.env.ADZEN_API_KEY!,
});
// In your AG-UI event loop:
for await (const event of agentEventStream) {
const downstream = await adzen.processEvent(event);
for (const evt of downstream) {
emitToClient(evt);
}
}Client-side: render ad cards and bridge events
import { AdzenCard, dispatchPlacementEvents } from "@adzenai/ai/copilotkit/react";
// In your AG-UI event handler on the client:
dispatchPlacementEvents(events);
// In your message list:
{messages.map((msg) => (
<div key={msg.id}>
<AssistantMessage content={msg.content} />
<AdzenCard messageId={msg.id} />
</div>
))}Choose your path
What Adzen captures
From the AG-UI event stream, Adzen captures:
- Complete assistant message text (buffered per
messageId) - Final custom events as a fallback content source for agents that emit structured output
- Viewability signals when ads are rendered and visible in the viewport
What your users see
After integration, the CopilotKit chat shows:
- Assistant messages streaming normally with zero added latency
- A sponsored ad card below each assistant message (when the Adzen API returns a match)
- Viewability-tracked impressions that fire after the ad is visible for the configured threshold
- Click-through links to advertiser destinations
Next
- Quick start — your first matched ad in an existing app.
- Read How it works for architecture details.
- Configure runtime behavior in Configuration.