SDK Examples
These SDK-style examples are copy/paste ready and cover:
- Fetching ads via
POST /in-chat-recs - Rendering selected ads
- Firing impression pixels using
tracking.reportServed+&pos=...
Common Inputs
Base URL
https://mv.outbrain.com/Multivac/api/in-chat-recs
Required query params
keycontentUrlwidgetJSIdcors=truetestMode=true(optional)
Body example
{
"keywords": ["investing", "savings"],
"iabCategories": ["IAB13"]
}
1) JavaScript / TypeScript (Browser)
type InChatRecsRequestBody = {
keywords?: string[];
iabCategories?: string[];
};
type AdDocument = {
url: string;
thumbnail_url: string;
content: string;
source_display_name: string;
target_domain: string;
pos: number;
cta?: string;
};
type InChatRecsResponse = {
documents: AdDocument[];
tracking?: {
reportServed?: string;
};
};
export async function fetchInChatAds(params: {
apiKey: string;
contentUrl: string;
widgetJSId: string;
testMode?: boolean;
body: InChatRecsRequestBody;
}): Promise<InChatRecsResponse> {
const { apiKey, contentUrl, widgetJSId, testMode, body } = params;
const url = new URL("https://mv.outbrain.com/Multivac/api/in-chat-recs");
url.searchParams.set("key", apiKey);
url.searchParams.set("contentUrl", contentUrl);
url.searchParams.set("widgetJSId", widgetJSId);
url.searchParams.set("cors", "true");
if (testMode) url.searchParams.set("testMode", "true");
const res = await fetch(url.toString(), {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error(`InChatRecs API failed: ${res.status} ${res.statusText}`);
}
return res.json();
}
export function reportImpressions(args: {
reportServedUrl?: string;
displayedPositions: number[];
}) {
const { reportServedUrl, displayedPositions } = args;
if (!reportServedUrl || displayedPositions.length === 0) return;
const posParam = displayedPositions.join("-");
const pixelUrl = `${reportServedUrl}&pos=${posParam}`;
navigator.sendBeacon(pixelUrl);
}
// Example usage
(async () => {
const data = await fetchInChatAds({
apiKey: "YOUR_KEY",
contentUrl: "test.com",
widgetJSId: "APP_12",
testMode: true,
body: { keywords: ["finance"], iabCategories: ["IAB13"] },
});
const displayed = data.documents.slice(0, 2);
displayed.forEach((ad) => {
console.log(`${ad.content} | Sponsored by ${ad.source_display_name}`);
});
reportImpressions({
reportServedUrl: data.tracking?.reportServed,
displayedPositions: displayed.map((a) => a.pos),
});
})();
2) Node.js (Server-side)
Since
navigator.sendBeaconisn’t available in Node, fire the pixel via a GET request.
import fetch from "node-fetch";
export async function fetchInChatAds({
apiKey,
contentUrl,
widgetJSId,
testMode = false,
body,
}) {
const url = new URL("https://mv.outbrain.com/Multivac/api/in-chat-recs");
url.searchParams.set("key", apiKey);
url.searchParams.set("contentUrl", contentUrl);
url.searchParams.set("widgetJSId", widgetJSId);
url.searchParams.set("cors", "true");
if (testMode) url.searchParams.set("testMode", "true");
const res = await fetch(url.toString(), {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error(`API failed: ${res.status} ${res.statusText}`);
}
return res.json();
}
export async function reportImpressions(reportServedUrl, displayedPositions) {
if (!reportServedUrl || displayedPositions.length === 0) return;
const pixelUrl = `${reportServedUrl}&pos=${displayedPositions.join("-")}`;
await fetch(pixelUrl, { method: "GET" });
}
// Example usage
(async () => {
const data = await fetchInChatAds({
apiKey: "YOUR_KEY",
contentUrl: "test.com",
widgetJSId: "APP_12",
testMode: true,
body: { keywords: ["investing"], iabCategories: ["IAB13"] },
});
const displayed = [data.documents[0], data.documents[2]].filter(Boolean);
await reportImpressions(
data.tracking?.reportServed,
displayed.map((a) => a.pos)
);
console.log("Rendered ads:", displayed.map((a) => a.content));
})();
3) Python (requests)
import requests
from typing import List, Dict, Any, Optional
BASE_URL = "https://mv.outbrain.com/Multivac/api/in-chat-recs"
def fetch_in_chat_ads(
api_key: str,
content_url: str,
widget_js_id: str,
body: Dict[str, Any],
test_mode: bool = False
) -> Dict[str, Any]:
params = {
"key": api_key,
"contentUrl": content_url,
"widgetJSId": widget_js_id,
"cors": "true",
}
if test_mode:
params["testMode"] = "true"
resp = requests.post(
BASE_URL,
params=params,
json=body,
timeout=10
)
resp.raise_for_status()
return resp.json()
def report_impressions(report_served_url: Optional[str], positions: List[int]) -> None:
if not report_served_url or not positions:
return
pixel_url = f"{report_served_url}&pos={'-'.join(map(str, positions))}"
requests.get(pixel_url, timeout=5)
if __name__ == "__main__":
data = fetch_in_chat_ads(
api_key="YOUR_KEY",
content_url="test.com",
widget_js_id="APP_12",
test_mode=True,
body={
"keywords": ["finance", "savings"],
"iabCategories": ["IAB13"]
}
)
docs = data.get("documents", [])
displayed = docs[:2]
displayed_positions = [ad["pos"] for ad in displayed]
print("Rendered ads:", [ad["content"] for ad in displayed])
report_impressions(
report_served_url=data.get("tracking", {}).get("reportServed"),
positions=displayed_positions
)
4) Java (OkHttp)
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class InChatRecsSdk {
private static final String BASE_URL = "https://mv.outbrain.com/Multivac/api/in-chat-recs";
private final OkHttpClient client = new OkHttpClient();
public JSONObject fetchAds(String apiKey, String contentUrl, String widgetJSId, boolean testMode, JSONObject body) throws IOException {
HttpUrl.Builder urlBuilder = HttpUrl.parse(BASE_URL).newBuilder()
.addQueryParameter("key", apiKey)
.addQueryParameter("contentUrl", contentUrl)
.addQueryParameter("widgetJSId", widgetJSId)
.addQueryParameter("cors", "true");
if (testMode) urlBuilder.addQueryParameter("testMode", "true");
Request request = new Request.Builder()
.url(urlBuilder.build())
.post(RequestBody.create(body.toString(), MediaType.parse("application/json")))
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("API failed: " + response.code());
return new JSONObject(response.body().string());
}
}
public void reportImpressions(String reportServedUrl, List<Integer> positions) throws IOException {
if (reportServedUrl == null || positions.isEmpty()) return;
StringBuilder pos = new StringBuilder();
for (int i = 0; i < positions.size(); i++) {
if (i > 0) pos.append("-");
pos.append(positions.get(i));
}
String pixelUrl = reportServedUrl + "&pos=" + pos;
Request request = new Request.Builder()
.url(pixelUrl)
.get()
.build();
client.newCall(request).execute().close();
}
public static void main(String[] args) throws Exception {
InChatRecsSdk sdk = new InChatRecsSdk();
JSONObject body = new JSONObject()
.put("keywords", new JSONArray().put("finance"))
.put("iabCategories", new JSONArray().put("IAB13"));
JSONObject data = sdk.fetchAds("YOUR_KEY", "test.com", "APP_12", true, body);
JSONArray docs = data.getJSONArray("documents");
JSONObject first = docs.getJSONObject(0);
JSONObject third = docs.length() > 2 ? docs.getJSONObject(2) : null;
List<Integer> displayed = new ArrayList<>();
displayed.add(first.getInt("pos"));
if (third != null) displayed.add(third.getInt("pos"));
String reportServed = data.optJSONObject("tracking").optString("reportServed", null);
sdk.reportImpressions(reportServed, displayed);
System.out.println("Rendered ad: " + first.getString("content"));
}
}
5) cURL (Quick Test)
curl -X POST "https://mv.outbrain.com/Multivac/api/in-chat-recs?key=YOUR_KEY&contentUrl=test.com&widgetJSId=APP_12&cors=true&testMode=true" -H "Content-Type: application/json" -d '{"keywords":["finance"],"iabCategories":["IAB13"]}'
Pixel example:
curl -X GET "https://mcdp-nldc1.outbrain.com/writePartialStats?token=...&pos=0-2"