Skip to content

Quickstart: Serve ads with the Node SDK

This quickstart shows you how to serve in-chat ads from your own Node.js code with @advertising-chat/sdk, a typed client for the Fetch API. Your code decides where ads appear. It takes about five minutes. To let an agent decide instead, see the MCP quickstart.

Before you begin

  1. Get an Advertising.chat account. If you don't have one, request access.
  2. In the console, in the Monetize section, click Get Started, and copy your key from 1 ยท Your fetch key. Keep it on your server.
  3. Install Node.js 18 or later.

Install the SDK

npm install @advertising-chat/sdk

The package includes TypeScript types and has no runtime dependencies.

Fetch an ad

import { AdChat, UniversalAdPayload } from '@advertising-chat/sdk';

const adchat = new AdChat({ apiKey: process.env.ADCHAT_FETCH_KEY! });

const ad = await adchat.fetchAd<UniversalAdPayload>({
  subscriber: sessionId, // anonymous id, used for frequency caps
  context: [
    { role: 'user', text: 'What is a good gift for a coffee lover?' },
    { role: 'assistant', text: 'A quality burr grinder is a great pick.' },
  ],
});

if (!ad) {
  // No ad fits this moment. Continue without one.
  return;
}

console.log(ad.messageId);       // use for event reporting
console.log(ad.payload.title);   // "Acme Coffee Grinder"
console.log(ad.payload.actions); // [{ text: 'Shop now', navigate: { url: 'https://...' } }]

context is either a string summary or an array of { role, text } turns. It selects this ad and is not kept as history. fetchAd resolves to null when no ad fits.

Render the ad for your channel

The default format is a channel-neutral card. Two helpers map it to common surfaces and add the Sponsored disclosure:

import { renderWebchat, renderWhatsApp } from '@advertising-chat/sdk';

const web = renderWebchat(ad.payload);
// { text, imageUrl, buttons: [{ label, url, postbackData, id }], disclosure: 'Sponsored' }

const wa = renderWhatsApp(ad.payload);
// A WhatsApp Cloud API message object with the footer "Sponsored": a link
// button, or up to three reply buttons when the ad has replies.
// Send it with your recipient: { ...wa, to }

To receive a channel's native message from the server instead, pass format to fetchAd with one of the values in Render formats, such as sms or rcs-google, and forward ad.payload to your gateway.

Track clicks and conversions

The action URLs in the payload are click-tracking links. Present them unchanged, and each tap is recorded before the person reaches the advertiser.

Report other engagement explicitly:

// The person acted on the ad outside a tracked link:
await adchat.recordEvent({ messageId: ad.messageId, type: 'click' });

// The person completed the advertised action:
await adchat.recordConversion({
  messageId: ad.messageId,
  name: 'purchase',
  value: 19.99,
  currency: 'USD',
});

Both methods resolve with no value on success and throw an AdChatApiError, with status and reason, on failure.

Report reply taps

Some ads offer replies, such as "Add it" and "No thanks", instead of a link. A tap comes back to your code as the person's next message, carrying the reply's postback data. Pass it to recordInteraction:

import { messengerPostbackData, whatsAppPostbackData } from '@advertising-chat/sdk';

// Messenger webhook, for each `messaging` event:
const fromMessenger = messengerPostbackData(event);

// WhatsApp webhook, for each message in `value.messages`:
const fromWhatsApp = whatsAppPostbackData(message);

// Webchat: the tapped button's `postbackData` from renderWebchat.

const postbackData = fromMessenger ?? fromWhatsApp;
if (postbackData) {
  await adchat.recordInteraction(postbackData);
}

On RCS, pass suggestionResponse.postbackData, after checking it with isAdPostbackData. A reply that accepts or declines an offer records the person's answer, which the advertiser's rules can use. See Responses to an offer.

What's next