A lightweight vanilla JavaScript SDK with Shadow DOM isolation, session tracking, and auto-fill.
Add the script tag to your HTML page, ideally before your application code:
<script src="__BASE_URL__/sdk/intentara.js"></script> intentara.init(config)Initialize the SDK with your API key. Call this once before using any other method. Automatically generates an anonymous session ID for analytics (in-memory only — no cookies or localStorage).
| Parameter | Type | Description |
|---|---|---|
| apiKey required | string | Your Intentara public publisher key (starts with pub_). |
| baseUrl optional | string | Override the API base URL. Defaults to __BASE_URL__. Use an HTTPS origin in production. |
intentara.init({
apiKey: 'pub_XXXX',
}); intentara.getAd(options)Fetch the most relevant ad for a given conversation context. Returns a Promise<Ad | null>.
| Parameter | Type | Description |
|---|---|---|
| context required | string | The conversation context text. Send the existing chat history plus the current user input so you can request the ad before the LLM response is ready. |
| signal optional | AbortSignal | An AbortSignal to cancel the request. Useful for SPA cleanup in useEffect or route changes. |
const context = [...chatHistory, currentUserInput].join('\n');
const ad = await intentara.getAd({
context,
});
if (ad) {
console.log(ad.name); // Creative name
console.log(ad.text); // Ad copy
console.log(ad.targetUrl); // Click-through URL
console.log(ad.imageUrl); // Optional image
} With AbortController (for SPA cleanup):
const controller = new AbortController();
const ad = await intentara.getAd({
context: 'running shoes for marathon training',
signal: controller.signal,
});
// Cancel if needed (e.g., on route change)
controller.abort(); The returned ad object has this structure:
{
id: string; // Creative ID
name: string; // Creative name
text: string | null; // Ad copy text
imageUrl: string | null; // Ad image URL
impressionUrl: string; // Impression tracking pixel URL
targetUrl: string; // Click-through URL (with tracking)
score: number; // Relevance score
} intentara.render(ad, element, options?)Render an ad into a DOM element using Shadow DOM for style isolation. Impression tracking is handled automatically by loading ad.impressionUrl during rendering.
| Parameter | Type | Description |
|---|---|---|
| ad required | object | The ad object returned by getAd(). |
| element required | HTMLElement | The DOM element to render the ad into. |
| options.template optional | string | "card" (default) or "native". Card shows a full ad card with image, title, description, and CTA. Native renders a compact inline text link. |
| options.position optional | string | "inline" (default — replaces content), "suffix" (appends), or "prefix" (prepends). |
// Card template (default) — full ad card
intentara.render(ad, document.querySelector('#ad-slot'));
// Native template — compact inline text link
intentara.render(ad, document.querySelector('#ad-slot'), {
template: 'native',
});
// Suffix position — append after existing content
intentara.render(ad, document.querySelector('#chat-message'), {
template: 'card',
position: 'suffix',
}); intentara.process(options)Auto-fill: scans the DOM for all [data-intentara-slot] elements, fetches one ad, and renders it into every slot. Each slot can specify its own template via data-intentara-template.
| Parameter | Type | Description |
|---|---|---|
| context required | string | The conversation context for ad matching. |
| signal optional | AbortSignal | AbortSignal to cancel the request and prevent rendering. |
| onFill optional | function | Called with the ad object when an ad was successfully rendered. |
| onNoFill optional | function | Called when no matching ad was found (or no slots exist). |
| onError optional | function | Called with the error object if the request fails. |
<!-- In your HTML -->
<div data-intentara-slot></div>
<div data-intentara-slot data-intentara-template="native"></div> const context = [...chatHistory, currentUserInput].join('\n');
intentara.process({
context,
onFill: (ad) => console.log('Ad rendered:', ad.name),
onNoFill: () => console.log('No matching ad'),
onError: (err) => console.error('Ad error:', err),
}); A visually distinct ad card with optional image, an "Ad" label, and a "Learn more" call-to-action link.
┌──────────────────────────────────┐
│ [Image if available] │
│ ───────────────────────────── │
│ Ad │
│ Learn more → │
└──────────────────────────────────┘ A compact inline text link that blends with surrounding content. No image, minimal footprint.
Every rendered ad is wrapped in a Shadow DOM boundary. This means:
Customize ad appearance from outside the Shadow DOM by setting CSS variables on the slot element or any ancestor:
[data-intentara-slot] {
--intentara-bg: #ffffff; /* Card background */
--intentara-text: #1a1a1a; /* Text color */
--intentara-accent: #2563eb; /* CTA link color */
--intentara-border: #e5e7eb; /* Border color */
--intentara-radius: 8px; /* Border radius */
} Example — dark theme:
[data-intentara-slot] {
--intentara-bg: #1e293b;
--intentara-text: #f1f5f9;
--intentara-accent: #60a5fa;
--intentara-border: #334155;
--intentara-radius: 12px;
} init() generates a random session ID (crypto.randomUUID()) that is sent as an x-session-id header with every API request. This enables:
The session ID is stored in-memory only — it resets on page reload and never touches cookies or localStorage. No cookie banner required.
<!DOCTYPE html>
<html>
<head>
<title>My AI Chat</title>
<script src="__BASE_URL__/sdk/intentara.js"></script>
<style>
/* Optional: customize ad appearance */
[data-intentara-slot] {
--intentara-bg: #f8fafc;
--intentara-accent: #2563eb;
}
</style>
</head>
<body>
<div id="chat"></div>
<!-- Ad slots — auto-filled by process() -->
<div data-intentara-slot></div>
<script>
intentara.init({ apiKey: 'pub_XXXX' });
async function onUserSubmit(chatHistory, currentUserInput) {
document.getElementById('chat').textContent = currentUserInput;
const context = [...chatHistory, currentUserInput].join('\n');
await intentara.process({
context,
onFill: (ad) => console.log('Showing:', ad.name),
});
}
onUserSubmit(
[
'User: I need new running gear.',
'Assistant: Are you training for road races or trail runs?'
],
'User: Road races. I need shoes for marathon training.'
);
</script>
</body>
</html>