Add Adzen to CopilotKit
Use this guide when you already have a CopilotKit app and want Adzen to deliver contextual ads alongside assistant messages.
Adzen operates as AG-UI middleware. It does not wrap or modify the CopilotKit runtime — it processes the AG-UI event stream and adds adzen_placement custom events when an ad matches the assistant output.
Prerequisites
- A working CopilotKit app with an AG-UI-compatible backend agent
@copilotkit/react-coreand@copilotkit/runtime- Node.js
>=18 - Adzen API key
Step 1: Install Packages
npm install @adzenai/ai @adzenai/coreOr with pnpm:
pnpm add @adzenai/ai @adzenai/coreStep 2: Configure Environment
Add these variables to your .env:
ADZEN_API_KEY=your_api_keyStep 3: Add Middleware to the AG-UI Event Stream
Instantiate AdzenAsyncMiddleware and pipe every AG-UI event through processEvent(). The middleware passes all events through unchanged and appends adzen_placement custom events when an ad is returned.
Where you place this depends on your architecture:
Option A: Server-side (in your CopilotKit runtime route or AG-UI agent)
import { AdzenAsyncMiddleware } from "@adzenai/ai/copilotkit";
const adzen = new AdzenAsyncMiddleware({
apiKey: process.env.ADZEN_API_KEY!,
});
// In your AG-UI event processing loop:
for await (const event of upstreamEvents) {
const downstream = await adzen.processEvent(event);
for (const evt of downstream) {
sendToClient(evt);
}
}Option B: Client-side (processing events as they arrive from the CopilotKit runtime)
import { AdzenAsyncMiddleware } from "@adzenai/ai/copilotkit";
const adzen = new AdzenAsyncMiddleware({
apiKey: "your_api_key",
});
// In your event handler:
async function handleAgUiEvent(event: Record<string, unknown>) {
const downstream = await adzen.processEvent(event);
// Process all downstream events (original + any ad placements)
for (const evt of downstream) {
processEvent(evt);
}
}Step 4: Bridge Events to React
On the client, use dispatchPlacementEvents() to bridge AG-UI adzen_placement events to browser CustomEvents that the React components listen for:
import { dispatchPlacementEvents } from "@adzenai/ai/copilotkit/react";
// After processing events through the middleware:
dispatchPlacementEvents(downstream);This must run in a browser environment. Non-placement events are silently ignored.
Step 5: Render Ad Cards
Add <AdzenCard> below each assistant message in your chat UI:
import { AdzenCard } from "@adzenai/ai/copilotkit/react";
function MessageList({ messages }) {
return (
<>
{messages.map((msg) => (
<div key={msg.id}>
<MessageBubble content={msg.content} role={msg.role} />
{msg.role === "assistant" && (
<AdzenCard messageId={msg.id} />
)}
</div>
))}
</>
);
}AdzenCard returns null when there is no ad for the given messageId, so it is safe to render unconditionally after every assistant message.
Step 6: Verify a Live Request
Send a message through your CopilotKit UI, then verify:
- The assistant response streams normally with no added latency.
- After the message completes, an ad card appears below it (if the Adzen API returned a match).
- The ad card displays a headline, description, CTA, and optional creative image.
- After the card is visible for 1 second (default viewability threshold), an impression beacon fires.
- Check your Adzen dashboard for the impression event.
If the Adzen API returns no_match or is unreachable, no ad card appears and the assistant experience is unaffected.
Next Steps
- Configuration — customize timeouts, viewability thresholds, and placement behavior
- Integration Walkthrough — deep dive with custom rendering and advanced options
- Developer Guide — architecture and full API reference