Rotate ad creatives with the Select URL API

Use the Select URL API to take advantage of Shared Storage to determine what creative a user sees across sites.

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

With Select URL API creative rotation, you can store data, such as creative ID, view counts, and user interaction to determine which creative users see across different sites.

For more information on the underlying API and how selection works, explore the Select URL API documentation .

Try creative rotation

To experiment with creative rotation, make sure Select URL API and Shared Storage are enabled:

  • In chrome://settings/content/siteData , select Allow sites to save data on your device or Delete data sites have saved to your device when you close all windows .
  • In chrome://settings/adPrivacy/sites , select Site-suggested ads .

Try our Shared Storage live demo for a live version of the code samples in this document.

Demo with code samples

In this example:

  • creative-rotation.js is the third-party script defining the content to be rotated, along with any data that determines the next content to select and display, such as weights in this example. The publisher page executes this script. This script calls shared storage worklet to determine which content to display based on available data in storage and the list of URLs to select from.

  • creative-rotation-worklet.js is the third-party's shared storage worklet that looks up the rotation strategy, calculates what content to publish next, and returns that piece of content.

How the demo works

  1. When a user visits the publisher page, the page loads the third-party's creative-rotation.js script. The creative rotation script is responsible for loading and running the shared storage worklet. The script supplies the worklet call with a list of URLs to select from.
  2. In the worklet, if shared storage hasn't been initialized yet, the storage is initialized with the initial creative rotation strategy and creative index. The initial rotation strategy used in this demo is sequential strategy.
  3. The worklet reads the rotation mode from shared storage and returns the index of the next ad. In the case of sequential rotation mode, it also updates the creative index in shared storage with the new value to be used for the next call.The worklet returns a FencedFrameConfig or opaque URN object based on the resolveToConfig value used when calling selectURL .
  4. The creative-rotation script displays the selected ad in a Fenced Frame or an iframe. See the render an ad document for details on return types .
  5. When a user changes the rotation mode, the shared storage worklet updates the creative rotation mode value stored in shared storage.
  6. When reloading the publisher page, steps 1-4 are repeated enabling the selection of the next ad to be viewed based on the selected rotation strategy

Code samples

The following are the code samples for creative-rotation.js and creative-rotation-worklet.js .

creative-rotation.js

  const 
  
 contentProducerUrl 
  
 = 
  
 'https://your-server.example' 
 ; 
 // Ad config with the URL of the ad, a probability weight for rotation, and the clickthrough rate. 
 const 
  
 DEMO_AD_CONFIG 
  
 = 
  
 [ 
  
 { 
  
 url 
 : 
  
 ` 
 ${ 
 contentProducerUrl 
 } 
 /ads/ad-1.html` 
 , 
  
 weight 
 : 
  
 0.7 
 , 
  
 }, 
  
 { 
  
 url 
 : 
  
 ` 
 ${ 
 contentProducerUrl 
 } 
 /ads/ad-2.html` 
 , 
  
 weight 
 : 
  
 0.2 
 , 
  
 }, 
  
 { 
  
 url 
 : 
  
 ` 
 ${ 
 contentProducerUrl 
 } 
 /ads/ad-3.html` 
 , 
  
 weight 
 : 
  
 0.1 
 , 
  
 }, 
 ]; 
 async 
  
 function 
  
 setRotationMode 
 ( 
 rotationMode 
 ) 
  
 { 
  
 // Load the worklet module 
  
 const 
  
 creativeRotationWorklet 
  
 = 
  
 await 
  
 window 
 . 
 sharedStorage 
 . 
 createWorklet 
 ( 
  
 ` 
 ${ 
 contentProducerUrl 
 } 
 /url-selection/creative-rotation-worklet.js` 
 , 
  
 { 
  
 dataOrigin 
 : 
  
 'script-origin' 
  
 } 
  
 ); 
  
 await 
  
 creativeRotationWorklet 
 . 
 run 
 ( 
 'set-rotation-mode' 
 , 
  
 { 
  
 data 
 : 
  
 { 
  
 rotationMode 
  
 } 
  
 }); 
  
 console 
 . 
 log 
 ( 
 `creative rotation mode set to 
 ${ 
 rotationMode 
 } 
 ` 
 ); 
 } 
 async 
  
 function 
  
 injectAd 
 () 
  
 { 
  
 // Load the worklet module 
  
 const 
  
 creativeRotationWorklet 
  
 = 
  
 await 
  
 window 
 . 
 sharedStorage 
 . 
 createWorklet 
 ( 
  
 ` 
 ${ 
 contentProducerUrl 
 } 
 /url-selection/creative-rotation-worklet.js` 
 , 
  
 { 
  
 dataOrigin 
 : 
  
 'script-origin' 
  
 } 
  
 ); 
  
 const 
  
 urls 
  
 = 
  
 DEMO_AD_CONFIG 
 . 
 map 
 (({ 
  
 url 
  
 }) 
  
 = 
>  
 ({ 
  
 url 
  
 })); 
  
 // Resolve the selectURL call to a fenced frame config only when it exists on the page 
  
 const 
  
 resolveToConfig 
  
 = 
  
 typeof 
  
 window 
 . 
 FencedFrameConfig 
  
 !== 
  
 'undefined' 
 ; 
  
 // Run the URL selection operation to determine the next ad that should be rendered 
  
 const 
  
 selectedUrl 
  
 = 
  
 await 
  
 creativeRotationWorklet 
 . 
 selectURL 
 ( 
 'creative-rotation' 
 , 
  
 urls 
 , 
  
 { 
  
 data 
 : 
  
 DEMO_AD_CONFIG 
 , 
  
 resolveToConfig 
  
 }); 
  
 const 
  
 adSlot 
  
 = 
  
 document 
 . 
 getElementById 
 ( 
 'ad-slot' 
 ); 
  
 if 
  
 ( 
 resolveToConfig 
 && 
 selectedUrl 
  
 instanceof 
  
 FencedFrameConfig 
 ) 
  
 { 
  
 adSlot 
 . 
 config 
  
 = 
  
 selectedUrl 
 ; 
  
 } 
  
 else 
  
 { 
  
 adSlot 
 . 
 src 
  
 = 
  
 selectedUrl 
 ; 
  
 } 
 } 
 injectAd 
 (); 
 

creative-rotation-worklet.js

  class 
  
 SelectURLOperation 
  
 { 
  
 async 
  
 run 
 ( 
 urls 
 , 
  
 data 
 ) 
  
 { 
  
 // Initially set the storage to sequential mode for the demo 
  
 await 
  
 SelectURLOperation 
 . 
 seedStorage 
 (); 
  
 // Read the rotation mode from Shared Storage 
  
 const 
  
 rotationMode 
  
 = 
  
 await 
  
 sharedStorage 
 . 
 get 
 ( 
 'creative-rotation-mode' 
 ); 
  
 // Generate a random number to be used for rotation 
  
 const 
  
 randomNumber 
  
 = 
  
 Math 
 . 
 random 
 (); 
  
 let 
  
 index 
 ; 
  
 switch 
  
 ( 
 rotationMode 
 ) 
  
 { 
  
 /** 
 * Sequential rotation 
 * - Rotates the creatives in order 
 * - Example: A -> B -> C -> A ... 
 */ 
  
 case 
  
 'sequential' 
 : 
  
 const 
  
 currentIndex 
  
 = 
  
 await 
  
 sharedStorage 
 . 
 get 
 ( 
 'creative-rotation-index' 
 ); 
  
 index 
  
 = 
  
 parseInt 
 ( 
 currentIndex 
 , 
  
 10 
 ); 
  
 const 
  
 nextIndex 
  
 = 
  
 ( 
 index 
  
 + 
  
 1 
 ) 
  
 % 
  
 urls 
 . 
 length 
 ; 
  
 console 
 . 
 log 
 ( 
 `index = 
 ${ 
 index 
 } 
 / next index = 
 ${ 
 nextIndex 
 } 
 ` 
 ); 
  
 await 
  
 sharedStorage 
 . 
 set 
 ( 
 'creative-rotation-index' 
 , 
  
 nextIndex 
 . 
 toString 
 ()); 
  
 break 
 ; 
  
 /** 
 * Evenly-distributed rotation 
 * - Rotates the creatives with equal probability 
 * - Example: A=33% / B=33% / C=33% 
 */ 
  
 case 
  
 'even-distribution' 
 : 
  
 index 
  
 = 
  
 Math 
 . 
 floor 
 ( 
 randomNumber 
  
 * 
  
 urls 
 . 
 length 
 ); 
  
 break 
 ; 
  
 /** 
 * Weighted rotation 
 * - Rotates the creatives with weighted probability 
 * - Example: A=70% / B=20% / C=10% 
 */ 
  
 case 
  
 'weighted-distribution' 
 : 
  
 console 
 . 
 log 
 ( 
 'data = ' 
 , 
  
 JSON 
 . 
 stringify 
 ( 
 data 
 )); 
  
 // Find the first URL where the cumnulative sum of the weights 
  
 // exceed the random number. The array is sorted by the weight 
  
 // in descending order. 
  
 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 
 ; 
  
 } 
  
 console 
 . 
 log 
 ( 
 JSON 
 . 
 stringify 
 ({ 
  
 index 
 , 
  
 randomNumber 
 , 
  
 rotationMode 
  
 })); 
  
 return 
  
 index 
 ; 
  
 } 
  
 // Set the mode to sequential and set the starting index to 0. 
  
 static 
  
 async 
  
 seedStorage 
 () 
  
 { 
  
 await 
  
 sharedStorage 
 . 
 set 
 ( 
 'creative-rotation-mode' 
 , 
  
 'sequential' 
 , 
  
 { 
  
 ignoreIfPresent 
 : 
  
 true 
 , 
  
 }); 
  
 await 
  
 sharedStorage 
 . 
 set 
 ( 
 'creative-rotation-index' 
 , 
  
 0 
 , 
  
 { 
  
 ignoreIfPresent 
 : 
  
 true 
 , 
  
 }); 
  
 } 
 } 
 class 
  
 SetRotationModeOperation 
  
 { 
  
 async 
  
 run 
 ({ 
  
 rotationMode 
  
 }) 
  
 { 
  
 await 
  
 sharedStorage 
 . 
 set 
 ( 
 'creative-rotation-mode' 
 , 
  
 rotationMode 
 ); 
  
 } 
 } 
 // Register the operation as 'creative-rotation' 
 register 
 ( 
 'creative-rotation' 
 , 
  
 SelectURLOperation 
 ); 
 register 
 ( 
 'set-rotation-mode' 
 , 
  
 SetRotationModeOperation 
 ); 
 

Walkthrough with screenshots

  1. To access the Creatives Rotation using Select URL API and Shared storage, go to https://shared-storage-demo.web.app/ . Choose 'Creative Rotation' demo.

  2. Choose to explore the demo as 'Publisher A'. You will be redirected to https://shared-storage-demo-publisher-a.web.app/creative-rotation . The page loads numbered content based on the creative rotation data saved in Shared Storage, accessed through the Select URL API. The demo modes for creative rotation are sequential, even distribution and weighted distribution. The worklet executes the logic to select the content that appears in the iframe. The following image shows the publisher page.A screenshot showing the contents of the page for Publisher A https://shared-storage-demo-publisher-a.web.app/creative-rotation containing an iframe with an image of the number 1, controls to choose the creative rotation strategies sequential, even distribution and weighted distribution. There is also a text area describing the different creative rotation strategies and links to the iframe and worklet logics.

    A screenshot shows the Publisher A page with an image of the number 1 and controls to choose creative rotation strategies.

  3. To view what is stored in Shared Storage, navigate to Application -> Shared Storage in Chrome DevTools. Two entries are created for shared storage. An empty storage is available for the https://shared-storage-demo-publisher-a.web.app origin. This will contain storage specific to that origin and will remain empty for our demo since the publisher does not need to write to shared storage. Note that a similar storage will be created for Publisher B when you visit that page at a later time for the demo.A screenshot showing Chrome DevTools specifically the Application section, Highlighting the Shared Storage entries and showing the empty storage for the origin of

    Chrome DevTools shows empty Shared Storage for Publisher A.

  4. Another Shared Storage entry will be created for the https://shared-storage-demo-content-producer.web.app origin. This is the storage of the third-party iframe embedded on the publisher page. This storage will be used to share data between the two available publishers to coordinate creative selection. This shared storage will be used to save information about the shown creative and rotation strategy by saving two key-value pairs. The first key used in the demo is creative-rotation-index whose value is the current creative index in sequential mode. The second key is creative-rotation-mode which dictates the rotation strategy used.A screenshot showing the chrome Devtools specifically the shared storage for the origin https://shared-storage-demo-content-producer.web.app. The storage is not empty showing two key value pairs saved. The first key is creative-rotation-index with the value 1. The second saved key is creative-rotation-mode with the value

    A screenshot shows the Chrome DevTools shared storage with two key-value pairs: creative-rotation-index: 1 and creative-rotation-mode: "sequential."

  5. Refreshing the page while in sequential mode will result in showing the next creative in the sequence 1, 2, 3, 1, …, The value for the key creative-rotation-index will change according to the index of the shown creative while in sequential mode.A screenshot showing the

    A screenshot shows Publisher A's webpage and DevTools. The creative shown is 2, creative-rotation-mode is sequential, and creative-rotation-index is 2.

  6. Changing the creative rotation mode using the control buttons will update the value for key creative-rotation-mode into the corresponding strategy. This will be used by the worklet code to choose the next creative to be shown in the iframe. Note that the value saved for creative-rotation-index doesn"t change for rotation modes other than sequential.A screenshot showing the

    A screenshot shows Publisher A's webpage and DevTools. The creative shown is 1, creative-rotation-mode is weighted distribution, and creative-rotation-index is 2 (unused).

  7. Navigate to the page for "Publisher B" at https://shared-storage-demo-publisher-b.web.app/creative-rotation . In sequential mode the creative shown should be the next creative in the sequence shown when visiting the URL for "Publisher A". Inspecting the Shared Storage for the content producer, you can find that both "Publisher A" and "Publisher B" share the same storage and are using the settings there to select the next creative to show and the rotation strategy to use.A screenshot showing the

    Publisher B's webpage and DevTools. The Shared Storage creative is 3, the creative-rotation index is 3, and the creative-rotation-mode is sequential.

  8. The Shared Storage for "Publisher B" is empty, similar to "Publisher A"'s Shared Storage. screenshot showing Chrome DevTools specifically the Application section, Highlighting the Shared Storage entries and showing the empty storage for the Origin of

    Chrome DevTools showing empty Shared Storage for Publisher B origin.

    Use cases

    All available use cases for Select URL API can be found in this section. We'll continue to add examples as we receive feedback and discover new test cases.

    • Rotate ad creatives : Store data, such as creative ID and user interaction, to determine which creative users' see across different sites.
    • Select ad creatives by frequency : Use view count data to determine which creative users' see across different sites.
    • Run A/B testing : You can assign a user to an experiment group, then store that group in Shared Storage to be accessed cross-site.
    • Customize experience for known customers : Share custom content and calls-to-action based on a user's registration status or other user states.

Engage and share feedback

Note that the Select URL API proposal is under active discussion and development and subject to change.

We're eager to hear your thoughts on the Select URL API.

Stay Informed

  • Mailing List: Subscribe to our mailing list for the latest updates and announcements related to the Select URL and Shared Storage APIs.

Need Help?

Create a Mobile Website
View Site in Mobile | Classic
Share by: