Skip to main content

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

  • key
  • contentUrl
  • widgetJSId
  • cors=true
  • testMode=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.sendBeacon isn’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"