Measure user demographics

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 then use aggregated reporting to include that data in reports from other sites, such as your embedded content.

The Shared Storage API is a Privacy Sandbox proposal for general purpose, cross-site storage, which supports many possible use cases. Private Aggregation API is an output available in Shared Storage that lets you aggregate cross-site data.

Try user demographic measurement

To experiment with user demographic measurement with Shared Storage and Private Aggregation, confirm you're using Chrome Canary and Dev M107 or later. Enable all the Ad privacy APIs under chrome://settings/adPrivacy .

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

Experiment with code samples

You may want to measure certain demographics of the users who have seen your content across different sites, for example age range or geographical location. In this example, the content ID, age group ID, and the geography ID dimensions are encoded into the aggregation key (bucket), and the count is used as the aggregatable value. The summary report generated will provide information such as "Approximately 391 users who have seen the content ID 123 are between the age of 18-39 and are from Europe."

In this example:

  • demographic-measurement.js is loaded using a frame, and is responsible for loading the shared storage worklet.
  • demographic-measurement-worklet.js is the shared storage worklet that reads the demographics data in shared storage and sends a report using the Private Aggregation API.

store-demographic-data.js

(Runs at some point in time before the measurement is made to set the demographics data into Shared Storage)

  function 
  
 getDemogrationsData 
 () 
  
 { 
  
 // Collect age group and continent data 
  
 return 
  
 { 
  
 ageGroup 
 , 
  
 continent 
  
 } 
 } 
 async 
  
 function 
  
 storeDemographics 
 () 
  
 { 
  
 const 
  
 { 
  
 ageGroup 
 , 
  
 continent 
  
 } 
  
 = 
  
 getDemographicsData 
 (); 
  
 await 
  
 window 
 . 
 sharedStorage 
 . 
 set 
 ( 
 'age-group' 
 , 
  
 ageGroup 
 ); 
  
 await 
  
 window 
 . 
 sharedStorage 
 . 
 set 
 ( 
 'continent' 
 , 
  
 continent 
 ); 
 } 
 storeDemographics 
 (); 
 

demographic-measurement.js

  async 
  
 function 
  
 measureDemographics 
 () 
  
 { 
  
 // Load the Shared Storage worklet 
  
 await 
  
 window 
 . 
 sharedStorage 
 . 
 worklet 
 . 
 addModule 
 ( 
 'demographics-measurement-worklet.js' 
 ); 
  
 // Run the demographics measurement operation 
  
 await 
  
 window 
 . 
 sharedStorage 
 . 
 run 
 ( 
 'demographics-measurement' 
 , 
  
 { 
  
 data 
 : 
  
 { 
  
 contentId 
 : 
  
 '123' 
  
 } 
  
 }); 
 } 
 measureDemographics 
 (); 
 

demographic-measurement-worklet.js

  // Learn more about noise and scaling from the Private Aggregation fundamentals 
 // documentation on Chrome blog 
 const 
  
 SCALE_FACTOR 
  
 = 
  
 65536 
 ; 
 /** 
 * The bucket key must be a number, and in this case, it is just the ad campaign 
 * ID itself. For more complex bucket key construction, see other use cases in 
 * this demo. 
 */ 
 const 
  
 AGGREGATION_KEY_MAP 
  
 = 
  
 { 
  
 ageGroupId 
 : 
  
 { 
  
 '18-39' 
 : 
  
 '1' 
 , 
  
 '40-64' 
 : 
  
 '2' 
 , 
  
 '65+' 
 : 
  
 '3' 
 , 
  
 }, 
  
 continentId 
 : 
  
 { 
  
 africa 
 : 
  
 '1' 
 , 
  
 antarctica 
 : 
  
 '2' 
 , 
  
 asia 
 : 
  
 '3' 
 , 
  
 australia 
 : 
  
 '4' 
 , 
  
 europe 
 : 
  
 '5' 
 , 
  
 'north-america' 
 : 
  
 '6' 
 , 
  
 'south-america' 
 : 
  
 '7' 
 , 
  
 }, 
 }; 
 /** 
 * The aggregation key will be in the format of: 
 * contentId | ageGroupId | continentId 
 * 
 * For example, a user from Australia between the age of 40-64, who has 
 * seen the Content ID 321 will be represented by the key: 
 * 321 | 2 | 4 or 32124 
 */ 
 function 
  
 generateAggregationKey 
 ( 
 contentId 
 , 
  
 ageGroup 
 , 
  
 continent 
 ) 
  
 { 
  
 const 
  
 ageGroupId 
  
 = 
  
 AGGREGATION_KEY_MAP 
 . 
 ageGroupId 
 [ 
 ageGroup 
 ]; 
  
 const 
  
 continentId 
  
 = 
  
 AGGREGATION_KEY_MAP 
 . 
 continentId 
 [ 
 continent 
 ]; 
  
 const 
  
 aggregationKey 
  
 = 
  
 BigInt 
 ( 
 ` 
 ${ 
 contentId 
 }${ 
 ageGroupId 
 }${ 
 continentId 
 } 
 ` 
 ); 
  
 return 
  
 aggregationKey 
 ; 
 } 
 class 
  
 DemographicsMeasurementOperation 
  
 { 
  
 async 
  
 run 
 ( 
 data 
 ) 
  
 { 
  
 const 
  
 { 
  
 contentId 
  
 } 
  
 = 
  
 data 
 ; 
  
 // Read from Shared Storage 
  
 const 
  
 key 
  
 = 
  
 'has-reported-content' 
 ; 
  
 const 
  
 hasReportedContent 
  
 = 
  
 ( 
 await 
  
 sharedStorage 
 . 
 get 
 ( 
 key 
 )) 
  
 === 
  
 'true' 
 ; 
  
 const 
  
 ageGroup 
  
 = 
  
 await 
  
 sharedStorage 
 . 
 get 
 ( 
 'age-group' 
 ); 
  
 const 
  
 continent 
  
 = 
  
 await 
  
 sharedStorage 
 . 
 get 
 ( 
 'continent' 
 ); 
  
 // Don't report if a report has been sent already 
  
 if 
  
 ( 
 hasReportedContent 
 ) 
  
 { 
  
 return 
 ; 
  
 } 
  
 // Generate the aggregation key and the aggregatable value 
  
 const 
  
 bucket 
  
 = 
  
 generateAggregationKey 
 ( 
 contentId 
 , 
  
 ageGroup 
 , 
  
 continent 
 ); 
  
 const 
  
 value 
  
 = 
  
 1 
  
 * 
  
 SCALE_FACTOR 
 ; 
  
 // Send an aggregatable report using the Private Aggregation API 
  
 privateAggregation 
 . 
 contributeToHistogram 
 ({ 
  
 bucket 
 , 
  
 value 
  
 }); 
  
 // Set the report submission status flag 
  
 await 
  
 sharedStorage 
 . 
 set 
 ( 
 key 
 , 
  
 true 
 ); 
  
 } 
 } 
 // Register the operation 
 register 
 ( 
 'demographics-measurement' 
 , 
  
 DemographicsMeasurementOperation 
 ); 
  
 \ 
 

Engage and share feedback

Note that the Shared Storage API proposal is under active discussion and development and therefore subject to change.

We're eager to hear your thoughts on the Shared Storage API.

Stay Informed

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

Need Help?

Design a Mobile Site
View Site in Mobile | Classic
Share by: