Integration docs
How to embed the SmartAudiences widget and handle messages from the parent page. Prototype / pseudo-documentation.
Embed URL
Serve the atomic widget at:
http://localhost:3000/embed/widget?apiKey=<PUBLIC_KEY>&campaign_id=<required>&info=<optional>&font=<GoogleFontName>&bg=<hex>&text=<hex>&button=<hex>&buttonText=<hex>&poweredBy=1&setupNotice=1&prompt=<urlencoded>
Query parameters
| Param | Required | Description |
|---|---|---|
apiKey | Yes | Public API key. In this prototype any non-empty value is accepted; Apex uses the seeded demo key. |
campaign_id | Yes | DSP campaign identifier. Widget shows an error and will not run if omitted. Echoed on postMessage and webhooks. |
info | No | Opaque URL-encoded string (up to ~2KB). Stored and returned as-is on postMessage and webhooks. |
setupNotice | No | Show the “custom audiences take extra time” caption. 1 (default) or 0. |
font | No | Google Font family name (default: Instrument Sans). |
bg | No | Background color hex (default #ffffff). |
text | No | Text color hex. |
button | No | Primary button color hex. |
buttonText | No | Button label color hex. |
poweredBy | No | Show centered “Powered by inMarket” footer. 1/true (default) or 0/false. Widget UI is otherwise white-label (no SmartAudiences badge). |
prompt | No | Prefills the audience description textarea. |
Example iframe
<iframe id="sa-widget" src="http://localhost:3000/embed/widget?apiKey=a1b2c3d4-e5f6-4789-a012-3456789abcde&campaign_id=demo-campaign&font=Instrument%20Sans&bg=%23ffffff&text=%23212529&button=%2343A047&buttonText=%23ffffff&poweredBy=1&setupNotice=1" title="Audience builder" style="width:100%;min-height:720px;border:0;" ></iframe>
postMessage contract
When the user clicks Save audience, the widget posts to window.parent:
{
"source": "smartaudiences",
"type": "audience.saved",
"version": 1,
"payload": {
"audienceId": "<uuid>",
"name": "pickleball players",
"package": "large",
"devices": 37430954,
"description": "people who played pickleball",
"timeWindow": "1w",
"apiKey": "<public-key-used>",
"comments": "",
"refresh": "once",
"campaign_id": "camp_abc123",
"info": "",
"staged": true
}
}
package is one of: small, medium, large, xlarge. Save stages the audience; generation starts when the DSP launches the campaign.
Optional events
widget.ready— fired once the embed has loaded.audience.selected— fired when a size package is chosen (before save). Payload includes package + devices.
Parent listener example
const SA_ORIGIN = "http://localhost:3000";
window.addEventListener("message", (event) => {
// Production: always verify origin
if (event.origin !== SA_ORIGIN) return;
const data = event.data;
if (!data || data.source !== "smartaudiences") return;
if (data.type === "audience.saved") {
const { audienceId, name, package, devices } = data.payload;
// Attach to your campaign draft / form state
console.log("Audience saved", audienceId, name, package, devices);
}
if (data.type === "audience.selected") {
// Optional: highlight package choice before final save
}
if (data.type === "widget.ready") {
// Optional: hide loading shell
}
});
Webhooks
Configure a single HTTPS endpoint on the Webhooks page. After the DSP launches a campaign, each staged audience is generated asynchronously. When an audience is ready, we POST one event per audience to that URL.
This prototype: Send test event on the Webhooks page may POST to your URL. The Apex mock does not POST across apps — it only simulates completion locally.
{
"source": "smartaudiences",
"type": "audience.generated",
"version": 1,
"payload": {
"campaign_id": "camp_abc123",
"audience_id": "aud_…",
"info": "",
"delivery": {
"method": "s3",
"url": "https://files.inmarket.com/audiences/aud_….csv"
}
}
}
If delivery is SFTP, delivery is:
{
"method": "sftp",
"host": "sftp.example.com",
"path": "/inbound/audiences/aud_….csv",
"audience_id": "aud_…"
}
Signing (optional)
If you set a signing secret, requests include:
X-SmartAudiences-Signature: sha256=<hex(hmac-sha256(secret, raw_body))>
Verify the HMAC of the raw POST body before trusting the event.
Parent-aware behavior
- The embed does not show a campaign picker — the parent already knows the campaign context.
- Step 2 primary CTA is Save audience (not “Save & Distribute”).
- Your DSP should render any “selected audience” summary from the
audience.savedpayload.
Public key vs secret
The public API key is safe to place in the iframe src.
The secret must never go in the embed — it would be visible to end users.
Future design: when a user presses Generate, the widget (or parent) calls the DSP’s backend,
which holds the secret and authenticates the generate request with SmartAudiences.
That prevents stripping the iframe and calling generate from arbitrary sites.
See devnotes/future-apis.md in the monorepo.
Demo keys caveat
a1b2c3d4-e5f6-4789-a012-3456789abcde.
This keeps the local demo reliable without cross-app key sync. Documented in devnotes/demo-keys.md.