Creative rotation

Use a Shared Storage worklet to rotate creatives across sites.

Published on Updated on

The Shared Storage API is a Privacy Sandbox proposal for general purpose, cross-site storage, which supports many possible use cases. One such example is creative rotation, which is available to test in Chrome 104.0.5086.0 and later.

With creative rotation, you can store the creative rotation mode and other metadata to rotate a creative seen by users across different sites.

Try creative rotation

To experiment with creative rotation with Shared Storage, confirm you're using Chrome 104.0.5086.0 or later. Then enable the Privacy Sandbox Ads APIs experiment flag at chrome://flags/#privacy-sandbox-ads-apis.

Set Privacy Sandbox Ads APIs experiment to enabled to use these APIs

You can also enable Shared Storage with the --enable-features=PrivacySandboxAdsAPIsOverride,OverridePrivacySandboxSettingsLocalTesting,SharedStorageAPI,FencedFrames flag in the command line.

Experiment with code samples

The following code samples were created to demonstrate how the API may be used for the given use cases. These are not meant to be used in production.

An advertiser or a content producer may want to apply different strategies to a campaign, and rotate the contents or creatives to increase effectiveness. Shared storage can be used to run different rotation strategies, such as sequential rotation and evenly-distributed rotation, across different sites.

In this example:

  • creative-rotation.js is embedded in a frame. This script sets which ads are the most important ( weight), and calls to the worklet to determine which content should be displayed.
  • creative-rotation-worklet.js is the shared storage worklet that determines the weighted distribution for the contents and returns which should be displayed.

creative-rotation.js

// Ad config with the URL of the content, a probability weight for rotation, and the clickthrough rate.
const DEMO_CONTENT_CONFIG = [
{
url: 'https://your-server.example/contents/content-1.html',
weight: 0.7,
},
{
url: 'https://your-server.example/contents/content-2.html',
weight: 0.2,
},
{
url: 'https://your-server.example/contents/content-3.html',
weight: 0.1,
},
];

// Set the mode to sequential and set the starting index to 0.
async function seedStorage() {
await window.sharedStorage.set('content-rotation-mode', 'sequential', {
ignoreIfPresent: true,
});

await window.sharedStorage.set('content-rotation-index', 0, {
ignoreIfPresent: true,
});
}

async function injectAd() {
// Load the worklet module
await window.sharedStorage.worklet.addModule('content-rotation-worklet.js');

// Initially set the storage to sequential mode for the demo
seedStorage();

// Run the URL selection operation to determine the next content rendered.
const urls = DEMO_CONTENT_CONFIG.map(({ url }) => ({ url }));
const opaqueURL = await window.sharedStorage.selectURL('content-rotation', urls, { data: DEMO_CONTENT_CONFIG });

// Render the opaque URL into a fenced frame
document.getElementById('content-slot').src = opaqueURL;
}

injectAd();

creative-rotation-worklet.js

class SelectURLOperation {
async run(urls, data) {
// Read the rotation mode from Shared Storage
const rotationMode = await this.sharedStorage.get('content-rotation-mode');

// Generate a random number to be used for rotation
const randomNumber = Math.random();

let index;

switch (rotationMode) {
/**
* Sequential rotation
* - Rotates the contents in order
* - Example: A -> B -> C -> A ...
*/

case 'sequential':
const currentIndex = await this.sharedStorage.get('creative-rotation-index');
index = parseInt(currentIndex, 10);
const nextIndex = (index + 1) % urls.length;

await this.sharedStorage.set('content-rotation-index', nextIndex);
break;

/**
* Weighted rotation
* - Rotates the contentswith weighted probability
* - Example: A=70% / B=20% / C=10%
*/

case 'weighted-distribution':

// Sum the weights cumulatively, and find the first URL where the sum exceeds
// the random number. The array is sorted in descending order first.
let weightSum = 0;
const { url } = data
.sort((a, b) => b.weight - a.weight)
.find(({ weight }) => {
weightSum += weight;
return weightSum > randomNumber;
});

index = urls.indexOf(url);
break;

default:
index = 0;
}

return index;
}
}

register('content-rotation', SelectURLOperation);

Other use cases

Explore other Shared Storage use cases and code samples:

Generate reports with Private Aggregation

  • Unique reach measurement: Many content producers and advertisers often want to know how many unique people saw their content. You can use Shared Storage to report on the first time a user saw your ad, embedded video, publication, and prevent duplicative counting of that same user on a different site, giving you an aggregated noisy report of your approximate unique reach.
  • Demographics measurement: Content producers often want to understand the demographics of their audience. You can use Shared Storage to record user demographic data in a context where you have it, such as your first-party site, and use aggregated reporting to report on it across many other sites, such as embedded content.
  • K+ frequency measurement: Sometimes described as "effective frequency," there is often a minimum number views before a user will recognize or recall certain content (often in the context of advertisement views). You can use Shared Storage to build reports of unique users that have seen a piece of content at least K number of times.

URL selection

  • Frequency control: run a worklet script to select a URL from a provided list, based on the stored data, and then render that URL in a fenced frame. This has many possible uses, such as selecting new content when a frequency cap is reached.
  • A/B testing: You can assign a user to an experiment group, then store that group in Shared Storage to be accessed cross-site.
  • Creative rotation: You can store the creative rotation mode, and other metadata, to rotate the creatives across different sites.
  • Known customer for payment provider: You can store whether the user has registered on your site into shared storage, then render a different element based on that stored status.

These are only some of the possible use cases for Shared Storage. We'll continue to add examples as we receive feedback and discover new use cases.

Engage and share feedback

The Shared Storage proposal is under active discussion and subject to change in the future. If you try this API and have feedback, we'd love to hear it.

Updated on Improve article

We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.