Campaign SDK
Creative changes with hard boundaries
The SDK only touches containers and fields that your page declares. Campaign content arrives as inert JSON, is validated against the current DOM, and never becomes executable markup.
Declare the baseline
Keep your normal fallback content in the document. Mark one unambiguous container with data-tday-slot, then mark each replaceable descendant with a unique data-tday-field.
<section data-tday-slot="homepage-hero">
<p data-tday-field="eyebrow">Original eyebrow</p>
<h1 data-tday-field="title">Original title</h1>
<img data-tday-field="product" src="/original.webp" alt="Original product">
<a data-tday-field="cta" href="/original">Original CTA</a>
</section>Publish an inert manifest
A campaign arm can target the declared slot with version 1 JSON. The optional fingerprint binds the published creative to the expected template structure.
{
"version": 1,
"slots": [
{
"slot": "homepage-hero",
"fingerprint": "dom-v1-0123456789abcdef",
"fields": {
"eyebrow": {
"kind": "text",
"value": "Built for busy teams"
},
"title": {
"kind": "text",
"value": "Launch your next campaign"
},
"product": {
"kind": "image",
"src": "https://cdn.example.com/product.webp",
"alt": "The product on a desk"
},
"cta": {
"kind": "link",
"href": "https://example.com/signup",
"text": "Start now",
"target": "_self"
}
},
"classes": ["campaign-active"],
"cssVariables": { "--campaign-accent": "#ffb400" }
}
]
}Supported field kinds
textText content, allowlisted attributes, classes, and CSS variables.imageHTTP(S) source, required alt text, optional dimensions, and safe presentation fields.videoHTTP(S) source, poster, label, and bounded playback flags.linkHTTP(S) destination, optional text, and _self or _blank target.Bind to a template fingerprint
Use fingerprintSlot() while preparing the manifest. At runtime, a mismatch leaves the baseline untouched instead of applying content to an unexpected structure.
import { fingerprintSlot } from "@designtday/campaign-sdk";
const slot = document.querySelector('[data-tday-slot="homepage-hero"]');
if (slot) {
console.log(fingerprintSlot(slot));
}Use a headless decision
Set autoApply: false when your renderer owns the UI. The assignment exposes its signed token, IDs, channel, sanitized manifest, optional published page model, and destination URL. Report exposure only after your experience is actually visible.
import { init } from "@designtday/campaign-sdk";
const campaign = init({
siteKey: "td_pub_your_public_installation_key",
campaign: "homepage-launch",
autoApply: false,
consent: "granted",
});
const decision = await campaign.ready;
const assignment = decision?.assignments[0];
if (assignment) {
renderCampaignExperience(assignment.manifest, assignment.page);
campaign.expose(assignment.token);
}Automatic viewable exposure
With automatic application, an exposure is queued only after consent is granted and at least one applied slot remains at least 50 percent visible for one continuous second. Each assignment token is exposed at most once by that client instance. Browser exposure remains an unverified reporting event.
Continue reading