Intentara / Docs
Dashboard

Examples

Real-world integration patterns for common frameworks and environments.

Vanilla JS — Auto-Fill

The simplest integration. Mark slots in HTML, call process() once — one API call fills all slots.

html
<!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>

Vanilla JS — Manual Control

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.

html
<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>

React Integration

A React component using useEffect with AbortController for proper cleanup on unmount or context changes.

IntentaraAd.tsx
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:

tsx
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>
  );
}

Server-Side — Node.js

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.

node.js
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:

javascript
if (ad) {
  renderAd(ad);

  const pixel = new Image();
  pixel.src = ad.impressionUrl;
}

Server-Side — Python

Fetch ads using Python's requests library. Include x-session-id for session tracking.

python
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']}")
Server-side impression tracking When fetching ads server-side, always load the impressionUrl as an image pixel for impression tracking, regardless of ad type. The SDK handles this automatically.