Integration Guide
Learn how to integrate Cue into different types of applications and frameworks.
💡 Recommendation: New integrations should use the SSP API for better performance and future compatibility. Legacy examples are included for reference but are deprecated.
Chatbot Integration​
OpenAI Function Calling (SSP API)​
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const tools = [
{
type: "function",
function: {
name: "get_contextual_ad",
description: "Get a contextual advertisement based on conversation",
parameters: {
type: "object",
properties: {
messages: {
type: "array",
description: "Array of conversation messages",
items: {
type: "object",
properties: {
role: { type: "string", enum: ["user", "assistant"] },
content: { type: "string" }
}
}
},
countryCode: {
type: "string",
description: "Country code (ISO 3166-1 alpha-2)"
}
},
required: ["messages"]
}
}
}
];
async function getContextualAd(messages, countryCode = 'US') {
// Phase 1: Submit bid
const bidResponse = await fetch('https://app.oncue.ad/api/v1/ssp/bid', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.CUE_API_KEY
},
body: JSON.stringify({ countryCode, messages })
});
const bid = await bidResponse.json();
if (!bid || !bid.bidId) return null;
// Phase 2: Generate ad (if bid wins)
const adResponse = await fetch(`https://app.oncue.ad/api/v1/ssp/ad/${bid.bidId}`, {
headers: {
'X-API-Key': process.env.CUE_API_KEY
}
});
const ad = await adResponse.json();
return ad;
}
// In your chat completion
const completion = await openai.chat.completions.create({
model: "gpt-4",
messages: conversationHistory,
tools: tools,
tool_choice: "auto"
});
OpenAI Function Calling (Legacy - Deprecated)​
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const tools = [
{
type: "function",
function: {
name: "get_contextual_ad",
description: "Get a contextual advertisement based on conversation",
parameters: {
type: "object",
properties: {
context: {
type: "string",
description: "The conversation context"
},
userQuery: {
type: "string",
description: "The user's current question"
}
},
required: ["context", "userQuery"]
}
}
}
];
async function getContextualAd(context, userQuery) {
const response = await fetch('https://app.oncue.ad/api/v1/ad-serving/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CUE_API_KEY}`
},
body: JSON.stringify({
context: { conversation: context, userQuery },
placement: { type: 'inline', position: 'after_response' }
})
});
const adData = await response.json();
return adData.ads[0];
}
// In your chat completion
const completion = await openai.chat.completions.create({
model: "gpt-4",
messages: conversationHistory,
tools: tools,
tool_choice: "auto"
});
LangChain Integration​
from langchain.tools import BaseTool
from langchain.agents import initialize_agent, AgentType
from langchain.llms import OpenAI
import requests
class CueAdTool(BaseTool):
name = "get_contextual_ad"
description = "Get contextual advertisements based on conversation"
def _run(self, conversation: str, user_query: str) -> str:
response = requests.post(
'https://app.oncue.ad/api/v1/ad-serving/request',
headers={
'Content-Type': 'application/json',
'Authorization': f'Bearer {os.getenv("CUE_API_KEY")}'
},
json={
'context': {
'conversation': conversation,
'userQuery': user_query
},
'placement': {
'type': 'inline',
'position': 'after_response'
}
}
)
ad_data = response.json()
if ad_data['ads']:
ad = ad_data['ads'][0]
return f"Suggested: {ad['content']['headline']} - {ad['content']['description']}"
return "No relevant ads available"
# Initialize agent with Cue tool
llm = OpenAI(temperature=0)
tools = [CueAdTool()]
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
Web Application Integration​
React Component (SSP API)​
import React, { useState, useEffect } from 'react';
const CueAd = ({ messages, countryCode = 'US', onAdClick }) => {
const [ad, setAd] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchAd = async () => {
if (!messages || messages.length === 0) return;
setLoading(true);
try {
// Phase 1: Submit bid
const bidResponse = await fetch('/api/cue/bid', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages, countryCode })
});
const bid = await bidResponse.json();
if (!bid || !bid.bidId) {
setLoading(false);
return;
}
// Phase 2: Generate ad (simulate winning auction)
const adResponse = await fetch(`/api/cue/ad/${bid.bidId}`);
const adData = await adResponse.json();
if (adData) {
setAd(adData);
}
} catch (error) {
console.error('Failed to fetch ad:', error);
} finally {
setLoading(false);
}
};
fetchAd();
}, [messages, countryCode]);
const handleClick = () => {
if (ad && ad.redirectUrl) {
window.open(ad.redirectUrl, '_blank');
onAdClick?.(ad);
}
};
if (loading) return <div className="ad-loading">Loading ad...</div>;
if (!ad) return null;
return (
<div className="cue-ad" onClick={handleClick}>
<div className="ad-content">
<p>{ad.adText}</p>
<button className="ad-cta">Learn More</button>
</div>
<div className="ad-label">Sponsored</div>
</div>
);
};
export default CueAd;
React Component (Legacy - Deprecated)​
import React, { useState, useEffect } from 'react';
const CueAd = ({ conversation, userQuery, onAdClick }) => {
const [ad, setAd] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchAd = async () => {
if (!conversation || !userQuery) return;
setLoading(true);
try {
const response = await fetch('/api/cue/request-ad', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ conversation, userQuery })
});
const adData = await response.json();
if (adData.ads && adData.ads.length > 0) {
setAd(adData.ads[0]);
// Track impression
fetch(`/api/cue/impression/${adData.ads[0].id}`, { method: 'POST' });
}
} catch (error) {
console.error('Failed to fetch ad:', error);
} finally {
setLoading(false);
}
};
fetchAd();
}, [conversation, userQuery]);
const handleClick = () => {
if (ad) {
// Track click
fetch(`/api/cue/click/${ad.id}`, { method: 'POST' })
.then(response => response.json())
.then(data => {
window.open(data.redirectUrl, '_blank');
onAdClick?.(ad);
});
}
};
if (loading) return <div className="ad-loading">Loading ad...</div>;
if (!ad) return null;
return (
<div className="cue-ad" onClick={handleClick}>
<div className="ad-content">
<h4>{ad.content.headline}</h4>
<p>{ad.content.description}</p>
<button className="ad-cta">{ad.content.callToAction}</button>
</div>
<div className="ad-label">Sponsored</div>
</div>
);
};
export default CueAd;
Next.js API Routes (SSP API)​
// pages/api/cue/bid.js
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { messages, countryCode } = req.body;
try {
const response = await fetch('https://app.oncue.ad/api/v1/ssp/bid', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.CUE_API_KEY
},
body: JSON.stringify({ countryCode, messages })
});
const bid = await response.json();
res.status(200).json(bid);
} catch (error) {
res.status(500).json({ error: 'Failed to submit bid' });
}
}
// pages/api/cue/ad/[bidId].js
export default async function handler(req, res) {
const { bidId } = req.query;
try {
const response = await fetch(`https://app.oncue.ad/api/v1/ssp/ad/${bidId}`, {
headers: {
'X-API-Key': process.env.CUE_API_KEY
}
});
const ad = await response.json();
res.status(200).json(ad);
} catch (error) {
res.status(500).json({ error: 'Failed to generate ad' });
}
}
Next.js API Routes (Legacy - Deprecated)​
// pages/api/cue/request-ad.js
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { conversation, userQuery } = req.body;
try {
const response = await fetch('https://app.oncue.ad/api/v1/ad-serving/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CUE_API_KEY}`
},
body: JSON.stringify({
context: { conversation, userQuery },
placement: { type: 'inline', position: 'after_response' }
})
});
const adData = await response.json();
res.status(200).json(adData);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch ad' });
}
}
// pages/api/cue/click/[adId].js
export default async function handler(req, res) {
const { adId } = req.query;
try {
const response = await fetch(`https://app.oncue.ad/api/v1/ad-serving/click/${adId}`);
const clickData = await response.json();
res.status(200).json(clickData);
} catch (error) {
res.status(500).json({ error: 'Failed to track click' });
}
}
Mobile App Integration​
React Native​
import React, { useState, useEffect } from 'react';
import { View, Text, TouchableOpacity, Linking, StyleSheet } from 'react-native';
const CueAd = ({ conversation, userQuery }) => {
const [ad, setAd] = useState(null);
const fetchAd = async () => {
try {
const response = await fetch('https://app.oncue.ad/api/v1/ad-serving/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${YOUR_API_KEY}`
},
body: JSON.stringify({
context: { conversation, userQuery },
placement: { type: 'inline', position: 'after_response' }
})
});
const adData = await response.json();
if (adData.ads && adData.ads.length > 0) {
setAd(adData.ads[0]);
// Track impression
fetch(`https://app.oncue.ad/api/v1/ad-serving/impression/${adData.ads[0].id}`);
}
} catch (error) {
console.error('Failed to fetch ad:', error);
}
};
const handleAdClick = async () => {
if (!ad) return;
try {
const response = await fetch(`https://app.oncue.ad/api/v1/ad-serving/click/${ad.id}`);
const clickData = await response.json();
Linking.openURL(clickData.redirectUrl);
} catch (error) {
console.error('Failed to track click:', error);
}
};
useEffect(() => {
if (conversation && userQuery) {
fetchAd();
}
}, [conversation, userQuery]);
if (!ad) return null;
return (
<TouchableOpacity style={styles.adContainer} onPress={handleAdClick}>
<Text style={styles.adHeadline}>{ad.content.headline}</Text>
<Text style={styles.adDescription}>{ad.content.description}</Text>
<Text style={styles.adCta}>{ad.content.callToAction}</Text>
<Text style={styles.adLabel}>Sponsored</Text>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
adContainer: {
backgroundColor: '#f5f5f5',
padding: 16,
margin: 8,
borderRadius: 8,
borderWidth: 1,
borderColor: '#e0e0e0'
},
adHeadline: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 4
},
adDescription: {
fontSize: 14,
marginBottom: 8
},
adCta: {
fontSize: 14,
color: '#007AFF',
fontWeight: '600'
},
adLabel: {
fontSize: 10,
color: '#666',
position: 'absolute',
top: 4,
right: 8
}
});
export default CueAd;
Discord Bot Integration​
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]
});
async function getContextualAd(conversation, userQuery) {
const response = await fetch('https://app.oncue.ad/api/v1/ad-serving/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CUE_API_KEY}`
},
body: JSON.stringify({
context: { conversation, userQuery },
placement: { type: 'inline', position: 'after_response' }
})
});
const adData = await response.json();
return adData.ads[0];
}
client.on('messageCreate', async (message) => {
if (message.author.bot) return;
// Only respond to messages that mention the bot
if (message.mentions.has(client.user)) {
const conversation = message.channel.messages.cache
.filter(msg => !msg.author.bot)
.last(5)
.map(msg => msg.content)
.join(' ');
const ad = await getContextualAd(conversation, message.content);
if (ad) {
const adEmbed = {
color: 0x0099ff,
title: ad.content.headline,
description: ad.content.description,
footer: { text: 'Sponsored' },
fields: [
{
name: 'Action',
value: `[${ad.content.callToAction}](${ad.tracking.clickUrl})`,
inline: true
}
]
};
await message.reply({ embeds: [adEmbed] });
// Track impression
fetch(`https://app.oncue.ad/api/v1/ad-serving/impression/${ad.id}`);
}
}
});
client.login(process.env.DISCORD_TOKEN);
API Gateway Integration​
AWS Lambda with API Gateway​
exports.handler = async (event) => {
const { conversation, userQuery } = JSON.parse(event.body);
try {
const response = await fetch('https://app.oncue.ad/api/v1/ad-serving/request', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CUE_API_KEY}`
},
body: JSON.stringify({
context: { conversation, userQuery },
placement: { type: 'inline', position: 'after_response' }
})
});
const adData = await response.json();
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(adData)
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: 'Failed to fetch ad' })
};
}
};
Error Handling Best Practices​
class CueAdService {
constructor(apiKey, options = {}) {
this.apiKey = apiKey;
this.baseUrl = options.baseUrl || 'https://app.oncue.ad/api/v1';
this.timeout = options.timeout || 5000;
this.retries = options.retries || 2;
}
async requestAd(context, placement, retryCount = 0) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const response = await fetch(`${this.baseUrl}/ad-serving/request`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify({ context, placement }),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const adData = await response.json();
return adData.ads[0] || null;
} catch (error) {
if (retryCount < this.retries && this.shouldRetry(error)) {
await this.delay(Math.pow(2, retryCount) * 1000); // Exponential backoff
return this.requestAd(context, placement, retryCount + 1);
}
console.error('Failed to fetch ad:', error);
return null;
}
}
shouldRetry(error) {
return error.name === 'AbortError' ||
(error.message.includes('500') || error.message.includes('502') || error.message.includes('503'));
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
Performance Optimization​
- Caching: Cache ads for similar contexts to reduce API calls
- Preloading: Request ads before they're needed
- Fallbacks: Always have fallback content when ads aren't available
- Timeout Handling: Set reasonable timeouts to avoid blocking your app
- Rate Limiting: Respect API rate limits with proper retry logic
Testing Integration​
// Mock for testing
const mockCueResponse = {
ads: [{
id: 'test-ad-123',
content: {
headline: 'Test Product',
description: 'Perfect for testing',
callToAction: 'Try Now'
},
tracking: {
clickUrl: 'https://app.oncue.ad/api/v1/ad-serving/click/test-ad-123'
}
}]
};
// Test your integration
describe('Cue Integration', () => {
beforeEach(() => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockCueResponse)
});
});
test('should fetch and display ad', async () => {
const ad = await getContextualAd('conversation', 'query');
expect(ad).toBeDefined();
expect(ad.content.headline).toBe('Test Product');
});
});