Reference
Complete signature and types for the JavaScript SDK's unified
requestAd method.
requestAd
Request an ad and render it into a target DOM element.
window.koah.requestAd(request)
Returns Promise<AdResult>.
Types
Full TypeScript signatures for the API surface. Drop these into your project for autocomplete and type-checking.
interface Dimensions {
/** Slot's maximum rendered width in CSS pixels. */
maxWidth?: number
/** Slot's maximum rendered height in CSS pixels. */
maxHeight?: number
}
type ConversationContext = {
type: 'conversation'
question: string
answer?: string
external_conversation_id?: string
}
type ArticleContext = {
type: 'article'
title: string
content: string
about?: string
}
type FeedContext = {
type: 'feed'
text: string
source?: string
description?: string
}
type StaticContext = {
type: 'static'
}
type AdContext =
| ConversationContext
| ArticleContext
| FeedContext
| StaticContext
type PreviewFormat =
| 'card_text'
| 'card_image'
| 'poll'
| 'expandable'
| 'rabbit_hole'
| 'catalog'
interface AdRequest {
target: Element
context: AdContext
dimensions?: Dimensions
/** @deprecated Use `dimensions` instead. */
size?: 'medium' | 'small'
experimentTag?: string
slot?: string
previewFormat?: PreviewFormat
signal?: AbortSignal
onFill?: () => void
onNoFill?: () => void
}
interface AdResult {
filled: boolean
fromCache?: boolean
}
type KoahAgeRange =
| 'unknown' | 'under-13'
| '13-15' | '16-17' | '18-20' | '21-24' | '25-29' | '30-34' | '35-39'
| '40-44' | '45-49' | '50-54' | '55-59' | '60-64' | '65-69' | '70-74' | '75+'
type KoahGender = 'unknown' | 'male' | 'female'
type KoahIncomeBracket =
| 'unknown' | '0-50' | '50-100' | '100-150' | '150-200' | '200+'
declare global {
interface Window {
koah: {
requestAd(request: AdRequest): Promise<AdResult>
setAgeRange(range: KoahAgeRange | { min: number; max: number }): void
setAge(age: number): void
setGender(gender: KoahGender): void
setIncomeBracket(bracket: KoahIncomeBracket): void
}
}
}
AdRequest
The single argument accepted by requestAd.
- Name
- target
- Type
- Element
- Description
DOM element to render the ad into. Calling
requestAdagain with the sametargetcleanly replaces any previously rendered ad in that slot.
- Name
- context
- Type
- AdContext
- Description
Content surrounding the ad, used for contextual matching. See AdContext. Pass
{ type: 'static' }for static placements.
- Name
- dimensions
- Type
- Dimensions
- Description
Maximum rendered dimensions of your slot. Each format defines one or more size variants with their own width/height bounds; Koah keeps any format that has at least one variant fitting within
maxWidth×maxHeightand picks from the remaining candidates. Both axes are optional — pass whichever bound you can describe; the omitted axis falls back to the default cap of 1440 × 550, not to unbounded. See Sizing for mobile and desktop for reading the slot's CSS size at request time.Omitting
dimensionsleaves the slot unbounded — dimension filtering is skipped and every format the platform supports is in play. That's the recommended default whenever your slot can stretch; wider eligibility means more fills, and therefore revenue. Reach fordimensionsonly when your layout genuinely constrains what can render and in that case specify the maximum space available. Slots below the minimum supported floor (240 × 72) are rejected before the network call. See Sizing the Ad to Your Slot for the interactive playground and Format Bounds for the full variant table.window.koah.requestAd({ target: document.getElementById('ad-slot'), context: { type: 'conversation', question, answer }, dimensions: { maxWidth: 480, maxHeight: 300 }, })
- Name
- size
- Type
- 'medium' | 'small'
- Description
Deprecated.
requestAdignoressize. Replace it withdimensions.size: 'small'maps todimensions: { maxWidth: 384, maxHeight: 112 }.size: 'medium'maps todimensions: { maxWidth: 1440, maxHeight: 550 }.
- Name
- experimentTag
- Type
- string
- Description
Tag this request with an experiment variant for A/B testing. See Experiments.
- Name
- slot
- Type
- string
- Description
Tag this request with a registered slot name to break down reporting by placement. The slot must be registered in your publisher settings first — passing an unregistered slot rejects the request, resolving with
{ filled: false }and callingonNoFill. See Slots.
- Name
- previewFormat
- Type
- PreviewFormat
- Description
Force a specific ad format for development preview. Bypasses normal ad selection and returns a specimen ad in the requested format. See Preview Formats.
- Name
- signal
- Type
- AbortSignal
- Description
Cancel an in-flight request. See Request Cancellation.
- Name
- onFill
- Type
- () => void
- Description
Called when an ad is successfully served.
- Name
- onNoFill
- Type
- () => void
- Description
Called when no ad is available. Useful for ad mediation waterfalls.
AdContext
A discriminated union on type. context is required. Pass the shape that matches the content around the ad, or { type: 'static' } for static placements.
conversation
For user/LLM chat surfaces. Omit answer to request an ad alongside the user's question (before the LLM responds), or include it to match against the full exchange.
- Name
- type
- Type
- 'conversation'
- Description
- Name
- question
- Type
- string
- Description
The user's message to the LLM.
- Name
- answer
- Type
- string
- Description
The LLM's response. Optional.
- Name
- external_conversation_id
- Type
- string
- Description
Stable ID for the conversation this message belongs to. Optional.
article
For editorial and long-form content pages.
- Name
- type
- Type
- 'article'
- Description
- Name
- title
- Type
- string
- Description
The article title.
- Name
- content
- Type
- string
- Description
Article body text. Send an excerpt (500–1000 characters), not the full article.
- Name
- about
- Type
- string
- Description
A short description of what the article is about. Optional.
feed
For social feeds, community posts, and similar text surfaces.
- Name
- type
- Type
- 'feed'
- Description
- Name
- text
- Type
- string
- Description
The post or feed item text.
- Name
- source
- Type
- string
- Description
Origin of the post (e.g. community or author name). Optional.
- Name
- description
- Type
- string
- Description
Supplemental description of the post's container. Optional.
static
For placements with no surrounding content: homepages, landing pages, and sidebars.
- Name
- type
- Type
- 'static'
- Description
AdResult
The resolved value of the requestAd promise.
- Name
- filled
- Type
- boolean
- Description
trueif an ad was served and rendered into the target.
- Name
- fromCache
- Type
- boolean
- Description
trueif the response was served from Koah's backend cache rather than freshly ranked. Present only whenfilledistrue.
Format Bounds
See Ad formats for the sizing model. The tables below give the JavaScript SDK's exact per-variant pixel bounds.
Each format renders at one or more size variants, each with its own min/max width and height. A format stays eligible for your slot if any of its variants fits — so a tight slot can still admit card_text or card_image via their Small variant even when their Medium variant is too tall.
The eligibility threshold on each axis is the variant's minimum (when set) or maximum: the format needs that much room to render. Variants with nil thresholds are unconstrained on that axis.
Medium variants (used by every format):
| Format | min_width | max_width | min_height | max_height |
|---|---|---|---|---|
card_text | 240px | 768px | — | 400px |
card_image | 240px | 576px | — | 480px |
poll | 288px | 768px | — | 400px |
expandable | 288px | 768px | — | 400px |
rabbit_hole | 320px | 768px | — | 540px |
catalog | — | — | — | — |
Small variants (cards and catalog only):
| Format | min_width | max_width | min_height | max_height |
|---|---|---|---|---|
card_text | 240px | 384px | 72px | 112px |
card_image | 240px | 384px | 72px | 112px |
catalog | — | — | — | — |
The minimum slot the SDK will attempt to render any non-catalog format into is 240px wide × 72px tall. Below that, requestAd resolves with { filled: false } and calls onNoFill without hitting the network.
catalog has no dimensional gate today — it's a horizontally-scrolling format
that adapts to any reasonable slot.
Bound values are tied to designer-confirmed format breakpoints and may shift as the renderer evolves. Use them as a guide for slot sizing, not as a contract. The interactive Sizing the Ad to Your Slot playground stays in sync with the current values.
Request Cancellation
For single-page applications, cancel in-flight ad requests when users navigate away using AbortSignal:
const controller = new AbortController()
window.koah.requestAd({
target: document.getElementById('ad-slot'),
context: { type: 'conversation', question, answer },
signal: controller.signal,
})
// Cancel if user navigates away
controller.abort()
Common pattern for chat apps:
const requestControllers = new Map()
function switchConversation(conversationId) {
// Cancel previous conversation's pending requests
requestControllers.get(currentConversationId)?.abort()
// Create new controller for this conversation
const controller = new AbortController()
requestControllers.set(conversationId, controller)
window.koah.requestAd({
target: document.getElementById('ad-slot'),
context: {
type: 'conversation',
question,
answer,
external_conversation_id: conversationId,
},
signal: controller.signal,
})
}
React / effect-based frameworks: don't abort() from useEffect cleanup.
In development, React Strict Mode runs every effect as setup → cleanup → setup
to surface side-effect bugs. If you tie controller.abort() to the cleanup,
React aborts the request the instant after it starts — you'll see
AbortError: signal is aborted without reason and no ad will render. A
conversation ad request is one-shot: fire it once and only cancel on a genuine
navigation or conversation switch (as above), not on every component teardown.
In React, request once per slot with a ref guard and omit signal unless you're
cancelling on a real route change:
function KoahAd({ question, answer, conversationId }) {
const slotRef = useRef(null)
const requested = useRef(false)
useEffect(() => {
// Assumes the SDK script has loaded — see Installation for gating on
// `window.koah` (or load the script with `defer` instead of `async`).
if (requested.current || !slotRef.current || !window.koah) return
requested.current = true
window.koah.requestAd({
target: slotRef.current,
context: {
type: 'conversation',
question,
answer,
external_conversation_id: conversationId,
},
})
// No abort here: doing so would cancel the request under Strict Mode.
}, [question, answer, conversationId])
return <div ref={slotRef} />
}
Theme tokens
Set these on the theme object (window.koah_init.theme before load, or window.koah.theme at runtime) — see Appearance for usage.
| Token | Type | Default | Description |
|---|---|---|---|
colorScheme | 'light' | 'dark' | auto-detect | Color palette. Defaults to the user's system preference via prefers-color-scheme. |
presentationMode | 'borderless' | 'card' | 'card' | card adds a border and surface background. borderless blends into the host page. |
accentColor | string | '#0d0d0d' | Brand color used for CTA buttons and interactive highlights. |
fontFamily | string | 'inherit' | CSS font-family. 'inherit' uses the host page's font. |
maxWidth | string | '600px' | Maximum width of the ad container. |
hideCta | boolean | false | Hide the call-to-action button on card and expandable formats. |
Tokens apply consistently across every ad format and are forward-compatible with new formats.
Age range buckets
Strings accepted by setAgeRange for visitor attributes:
Gender values
Strings accepted by setGender for visitor attributes:
Income brackets
Strings accepted by setIncomeBracket for visitor attributes. Values are annual household income in thousands of USD: