Configuration
Sensible defaults, three places to tune.
The SDK has three configurable surfaces: the server-side fetchAdzenAd call,
the <AdzenCard> component, and the useAdImpressions hook. There is no
automatic environment-variable binding — your application reads environment
variables and passes them in.
Environment variables
These are recommended names. Your server code reads them and passes them to fetchAdzenAd.
Required
| Variable | Purpose |
|---|---|
ADZEN_API_KEY | Adzen API key for your publisher account. Read server-side only. |
Optional
| Variable | Default | Purpose |
|---|---|---|
ADZEN_API_URL | https://api.adzen.ai/v1/ai | Adzen API base URL. The SDK appends /process. The default targets the hosted API (AI endpoints under the /ai prefix, so /process resolves to https://api.adzen.ai/v1/ai/process). Override only if Adzen gives you a different base URL. |
ADZEN_LOCATION | — | DMA location code (e.g. "US-CA-803") sent for geo-targeting. |
ADZEN_PROFILE_ID | — | Publisher profile ID, sent as the X-Profile-Id header. Only needed if Adzen support asks you to set it. |
Example .env
ADZEN_API_KEY=your_api_key
ADZEN_LOCATION=US-CA-803fetchAdzenAd options
fetchAdzenAd(options: FetchAdzenAdOptions): Promise<AdzenPlacement | null> — from @adzenai/ai. Server-side (it sends the API key).
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
content | string | Yes | — | The text to match an ad against, sent as content. |
messageId | string | Yes | — | Identifier for this placement, sent as message_id. Any stable value (e.g. a message id or a UUID). |
apiKey | string | Yes | — | Adzen API key. Sent as the X-API-Key header. |
endpointUrl | string | No | "https://api.adzen.ai/v1/ai" | Adzen API base URL. The helper appends /process. Override only if Adzen gives you a different base URL. |
timeoutMs | number | No | 3000 | Max time (ms) before the fetch is aborted. Ignored when signal is provided. |
location | string | No | — | DMA location code sent as a top-level location field for geo-targeting. |
conversationId | string | No | — | Sent as conversation_id; links impressions to a conversation. |
profileId | string | No | — | Sent as the X-Profile-Id header. |
adUnitPosition | string | No | "chin" | Used as the placement’s adUnitPosition when the ad carries no placement. |
signal | AbortSignal | No | — | Caller-supplied abort signal. When set, timeoutMs is not applied. |
const placement = await fetchAdzenAd({
apiKey: process.env.ADZEN_API_KEY!,
content: assistantMessage,
messageId: msg.id,
location: process.env.ADZEN_LOCATION,
});AdzenCardProps
<AdzenCard> from @adzenai/ai/react. Props are dual-mode — supply either a resolved ad (generic usage) or a messageId (CopilotKit event-driven usage), not both.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
ad | AdzenPlacement | one of ad / messageId | — | A resolved placement (e.g. the result of fetchAdzenAd). The type doesn’t accept null, and fetchAdzenAd returns null on no match, so render the card only when you have a placement. |
messageId | string | one of ad / messageId | — | Look the ad up from placement events instead (CopilotKit). See the CopilotKit configuration. |
adUnitPosition | string | No | "chin" | Ad unit position label reported for this placement. |
viewabilityThresholdMs | number | No | 1000 | Milliseconds the ad must be continuously visible before the view impression fires. |
className | string | No | — | CSS class applied to the card’s root element. |
{placement && (
<AdzenCard ad={placement} viewabilityThresholdMs={2000} className="my-ad-card" />
)}The built-in card shows the advertiser avatar (from advertiser_image_url, falling back to the advertiser’s initial), the advertiser name, a “Relevant Ad” disclosure, the headline, and the CTA link (target="_blank", rel="noopener sponsored"). It does not render description — that field is available on the placement for custom rendering.
useAdImpressions
useAdImpressions(ad, options?) => { ref } from @adzenai/ai/react. For rendering your own markup while keeping Adzen impression tracking.
const { ref } = useAdImpressions(placement, {
adUnitPosition: "chin",
viewabilityThresholdMs: 1000,
});
// attach ref to the element that represents the ad| Option | Type | Default | Description |
|---|---|---|---|
adUnitPosition | string | "chin" | Ad unit position label reported for this placement. |
viewabilityThresholdMs | number | 1000 | Continuous-visibility time before the view beacon fires. |
Returns { ref } — attach it to your ad element. The render beacon fires once when the ad becomes available; the view beacon fires once the element has been continuously visible for the threshold. Both beacons are skipped when their impression URL is null. AdzenCard uses this hook internally.
Adzen API response format
The Adzen /process API returns:
{
"message_id": "msg_abc123",
"ads": [
{
"ad_id": 1071,
"title": "Local Coffee Co",
"cta": "Learn More",
"click_through_url": "https://api.adzen.ai/…/redirect/abc1234",
"advertiser_name": "Acme Corp",
"sponsor_logo_url": "https://example.com/logo.png",
"creative_url": "https://example.com/banner.jpg",
"description": "A great product",
"placement": "chin",
"render_impression_url": "https://api.adzen.ai/…/impressions/render",
"view_impression_url": "https://api.adzen.ai/…/impressions/view"
}
]
}fetchAdzenAd returns the first ad mapped to AdzenPlacement:
| API field | AdzenPlacement field |
|---|---|
ads[0].ad_id | ad_id (coerced to string) |
ads[0].title | headline |
ads[0].cta | cta_text |
ads[0].click_through_url | destination_url |
ads[0].advertiser_name | advertiser_name |
ads[0].sponsor_logo_url | advertiser_image_url |
ads[0].creative_url | creative_url |
ads[0].description | description |
ads[0].placement | adUnitPosition (falls back to the adUnitPosition option) |
ads[0].render_impression_url | render_impression_url |
ads[0].view_impression_url | view_impression_url |
ads.length === 0 | returns null |
Impression beacons
Both the built-in card and useAdImpressions fire impression beacons as client-side GET requests directly to the delivery API — no server proxy or auth headers required. The impression URLs are pre-built by the API and fired as-is.
- Render impression — fired on mount, as a
GETtorender_impression_url. - View impression — fired after the viewability threshold is met, as a
GETtoview_impression_url.
If render_impression_url or view_impression_url is null, that beacon is skipped. A beacon that fails is retried once after 1 second, then dropped silently.
Viewability
Viewability uses IntersectionObserver via @adzenai/core’s observeViewability():
| Setting | Default | Description |
|---|---|---|
| Intersection threshold | 1.0 | The ad must be 100% visible. Not configurable via AdzenCard / useAdImpressions. |
| Time threshold | 1000ms | Continuous-visibility time. Configurable via viewabilityThresholdMs. |
| Firing behavior | Once | The view impression fires once per ad instance. |
Error handling and silent degradation
Adzen never throws into your render tree. All failures are silent:
| Scenario | Behavior |
|---|---|
/process returns non-200 | fetchAdzenAd returns null |
/process times out | Aborted via AbortController → null |
| Network error | null |
/process returns empty ads | null |
ad is null | AdzenCard renders nothing; useAdImpressions is a no-op |
| Impression beacon fails | Single retry after 1 second, then swallowed |
Next
- Integration walkthrough — end-to-end wiring, custom rendering, verification
- How it works — architecture and full API reference
- Quick start — your first matched ad