Real-world integration patterns for common frameworks and environments.
The simplest integration. Mark slots in HTML, call process() once — one API call fills all slots.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Chat with Ads</title>
<script src="__BASE_URL__/sdk/intentara.js"></script>
<style>
.chat-message { margin: 1rem 0; padding: 0.75rem; border-radius: 8px; }
.user { background: #1e293b; color: #f1f5f9; }
.assistant { background: #0f172a; color: #f1f5f9; }
/* Customize ad appearance */
[data-intentara-slot] {
--intentara-bg: #1e293b;
--intentara-text: #f1f5f9;
--intentara-accent: #60a5fa;
--intentara-border: #334155;
margin-top: 0.75rem;
}
</style>
</head>
<body>
<div id="chat"></div>
<!-- Ad slots — auto-filled by process() -->
<div data-intentara-slot></div>
<div data-intentara-slot data-intentara-template="native"></div>
<script>
intentara.init({ apiKey: 'pub_XXXX' });
var chatHistory = [];
function addMessage(role, text) {
var chatEl = document.getElementById('chat');
var div = document.createElement('div');
div.className = 'chat-message ' + role;
div.textContent = text;
chatEl.appendChild(div);
}
async function handleUserInput(currentUserInput) {
addMessage('user', currentUserInput);
var context = chatHistory.concat(['User: ' + currentUserInput]).join('\n');
// Request the ad immediately after the user message
await intentara.process({
context: context,
onFill: (ad) => console.log('Ad rendered:', ad.name),
onNoFill: () => console.log('No matching ad found'),
});
chatHistory.push('User: ' + currentUserInput);
}
// Demo
chatHistory = [
'User: I want to upgrade my coffee setup.',
'Assistant: Are you looking for espresso or filter coffee gear?'
];
handleUserInput('Espresso. Can you recommend a good home machine?');
</script>
</body>
</html> Use getAd() and render() separately for full control over fetching and placement. This example requests the ad on user submit, before the assistant response is available.
<script src="__BASE_URL__/sdk/intentara.js"></script>
<div id="chat"></div>
<div id="ad-slot"></div>
<script>
intentara.init({ apiKey: 'pub_XXXX' });
var chatHistory = [
'User: I need new running gear.',
'Assistant: Are you training for road races or trail runs?'
];
async function handleUserInput(currentUserInput) {
var context = chatHistory.concat(['User: ' + currentUserInput]).join('\n');
// Fetch ad before waiting for the LLM response
const ad = await intentara.getAd({
context: context,
});
// Render with card template
if (ad) {
intentara.render(ad, document.getElementById('ad-slot'), {
template: 'card',
position: 'inline',
});
}
chatHistory.push('User: ' + currentUserInput);
}
handleUserInput('I need shoes for marathon training.');
</script> A React component using useEffect with AbortController for proper cleanup on unmount or context changes.
import { useEffect, useRef } from 'react';
// Load the SDK script once (add to index.html or load dynamically)
// <script src="__BASE_URL__/sdk/intentara.js"></script>
declare global {
interface Window {
intentara: {
init: (config: { apiKey: string; baseUrl?: string }) => void;
getAd: (opts: { context: string; signal?: AbortSignal }) => Promise<any>;
render: (ad: any, el: HTMLElement, opts?: { template?: string; position?: string }) => void;
process: (opts: {
context: string;
signal?: AbortSignal;
onFill?: (ad: any) => void;
onNoFill?: () => void;
onError?: (err: Error) => void;
}) => Promise<any>;
};
}
}
interface IntentaraAdProps {
context: string;
template?: 'card' | 'native';
className?: string;
}
export function IntentaraAd({ context, template = 'card', className }: IntentaraAdProps) {
const slotRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!context || !slotRef.current) return;
const controller = new AbortController();
window.intentara
.getAd({ context, signal: controller.signal })
.then((ad) => {
if (ad && slotRef.current) {
window.intentara.render(ad, slotRef.current, { template, position: 'inline' });
}
});
return () => controller.abort();
}, [context, template]);
return <div ref={slotRef} className={className} />;
} Usage in your chat component:
import { IntentaraAd } from './IntentaraAd';
// Initialize once (e.g., in your app entry point)
window.intentara.init({ apiKey: 'pub_XXXX' });
function PendingUserTurn({ chatHistory, currentUserInput }: Props) {
const context = [...chatHistory, currentUserInput].join('\n');
return (
<div>
<p>{currentUserInput}</p>
<IntentaraAd
context={context}
template="card"
className="mt-3"
/>
</div>
);
} Fetch ads server-side using Node.js fetch (Node 18+) and embed them in your response. Pass an x-session-id header for session analytics.
import { randomUUID } from 'node:crypto';
const API_KEY = process.env.INTENTARA_API_KEY;
const API_URL = 'https://platform.intentara.com/api/v1/public/creatives/by-context';
async function getIntentaraAd(context, sessionId) {
const res = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY,
'x-session-id': sessionId, // track session across requests
},
body: JSON.stringify({ context }),
});
if (!res.ok) return null;
return res.json();
}
// Example: request the ad as soon as the user submits a message
async function prepareChatTurn(chatHistory, currentUserInput) {
// Generate a session ID per user session
const sessionId = randomUUID();
const context = [...chatHistory, currentUserInput].join('\n');
// Request the ad before calling the model
const ad = await getIntentaraAd(context, sessionId);
return { sessionId, ad };
}
async function handleChat(chatHistory, currentUserInput) {
const { ad } = await prepareChatTurn(chatHistory, currentUserInput);
const aiResponse = await generateAssistantResponse(chatHistory, currentUserInput);
return {
message: aiResponse,
ad: ad ? {
text: ad.text,
url: ad.targetUrl,
imageUrl: ad.imageUrl,
impressionUrl: ad.impressionUrl,
} : null,
};
} When you render the ad yourself, fire the impression beacon after the ad is actually displayed:
if (ad) {
renderAd(ad);
const pixel = new Image();
pixel.src = ad.impressionUrl;
} Fetch ads using Python's requests library. Include x-session-id for session tracking.
import os
import uuid
import requests
API_KEY = os.environ["INTENTARA_API_KEY"]
API_URL = "https://platform.intentara.com/api/v1/public/creatives/by-context"
def get_intentara_ad(context: str, session_id: str) -> dict | None:
res = requests.post(
API_URL,
json={"context": context},
headers={
"Content-Type": "application/json",
"x-api-key": API_KEY,
"x-session-id": session_id,
},
)
if res.status_code != 200:
return None
return res.json()
# Example usage
session_id = str(uuid.uuid4())
ad = get_intentara_ad("I need running shoes for a marathon", session_id)
if ad:
print(f"Ad: {ad['text']}")
print(f"Link: {ad['targetUrl']}") impressionUrl as an image pixel for impression tracking, regardless of ad type. The SDK handles this automatically.