共有ストレージとプライベート集計の実装のクイックスタート

このドキュメントは、Shared Storage API と Private Aggregation API の使用に関するクイックスタート ガイドです。Shared Storage は値を保存し、Private Aggregation は集計可能なレポートを作成するため、両方の API を理解する必要があります。

対象者: 広告テクノロジー プロバイダと測定プロバイダ。

Shared Storage API

クロスサイト トラッキングを防止するため、ブラウザはローカル ストレージや Cookie など、あらゆる形式のストレージをパーティショニングし始めています。ただし、パーティション化されていないストレージが必要なユースケースもあります。Shared Storage API は、プライバシー保護の読み取りアクセスで、複数のトップレベル サイトで無制限の書き込みアクセスを提供します。

共有ストレージはコンテキスト オリジン(sharedStorage の呼び出し元)に制限されます。

Shared Storage にはオリジンごとの容量制限があり、各エントリの文字数にも上限があります。上限に達すると、それ以上の入力は保存されません。データ ストレージの上限については、共有ストレージの説明をご覧ください。

共有ストレージの呼び出し

広告テクノロジーは、JavaScript またはレスポンス ヘッダーを使用して共有ストレージに書き込むことができます。共有ストレージからの読み取りは、ワークレットと呼ばれる分離された JavaScript 環境内でのみ行われます。

  • JavaScript の使用: 広告テクノロジーは、JavaScript ワークレットの外部で、値の設定、追加、削除などの特定の共有ストレージ関数を実行できます。ただし、共有ストレージの読み取りやプライベート集計の実行などの関数は、JavaScript ワークレットを介して完了する必要があります。JavaScript ワークレットの外部で使用できるメソッドについては、提案された API サーフェス - ワークレットの外部をご覧ください。

    オペレーション中にワークレットで使用されるメソッドについては、提案された API サーフェス - ワークレット内をご覧ください。

  • レスポンス ヘッダーの使用

    JavaScript と同様に、レスポンス ヘッダーを使用して実行できるのは、共有ストレージでの値の設定、追加、削除などの特定の関数のみです。レスポンス ヘッダーで Shared Storage を操作するには、リクエスト ヘッダーに Shared-Storage-Writable: ?1 を含める必要があります。

    クライアントからリクエストを開始するには、選択した方法に応じて次のコードを実行します。

    • fetch() の使用

      fetch("https://a.example/path/for/updates", {sharedStorageWritable: true});
      
    • iframe または img タグを使用する

      <iframe src="https://a.example/path/for/updates" sharedstoragewritable></iframe>
      
    • iframe タグまたは img タグで IDL 属性を使用する

      let iframe = document.getElementById("my-iframe");
      iframe.sharedStorageWritable = true;
      iframe.src = "https://a.example/path/for/updates";
      

詳細については、共有ストレージ: レスポンス ヘッダーをご覧ください。

共有ストレージへの書き込み

Shared Storage に書き込むには、JavaScript ワークレットの内外から sharedStorage.set() を呼び出します。ワークレットの外部から呼び出された場合、データは呼び出し元のブラウジング コンテキストのオリジンに書き込まれます。ワークレット内から呼び出された場合、データはワークレットを読み込んだブラウジング コンテキストのオリジンに書き込まれます。設定された鍵の有効期限は、最終更新日から 30 日間です。

ignoreIfPresent フィールドは省略可能です。このタグが存在し、true に設定されている場合、キーがすでに存在する場合は更新されません。キーが更新されていない場合でも、set() 呼び出しから 30 日後にキーの有効期限が更新されます。

同じページ読み込みで同じキーを使用して共有ストレージに複数回アクセスすると、キーの値が上書きされます。キーで以前の値を保持する必要がある場合は、sharedStorage.append() を使用することをおすすめします。

  • JavaScript の使用

    ワークレットの外部:

    window.sharedStorage.set('myKey', 'myValue1', { ignoreIfPresent: true });
    // Shared Storage: {'myKey': 'myValue1'}
    window.sharedStorage.set('myKey', 'myValue2', { ignoreIfPresent: true });
    // Shared Storage: {'myKey': 'myValue1'}
    window.sharedStorage.set('myKey', 'myValue2', { ignoreIfPresent: false });
    // Shared Storage: {'myKey': 'myValue2'}
    

    同様に、ワークレット内では次のようになります。

    sharedStorage.set('myKey', 'myValue1', { ignoreIfPresent: true });
    
  • レスポンス ヘッダーの使用

    レスポンス ヘッダーを使用して共有ストレージに書き込むこともできます。これを行うには、レスポンス ヘッダーで Shared-Storage-Write を使用し、次のコマンドを実行します。

    Shared-Storage-Write : set;key="myKey";value="myValue";ignore_if_present
    
    Shared-Storage-Write : set;key="myKey";value="myValue";ignore_if_present=?0
    

    複数のアイテムはカンマで区切ることができ、setappenddeleteclear を組み合わせることができます。

    Shared-Storage-Write :
    set;key="hello";value="world";ignore_if_present, set;key="good";value="bye"
    

値を追加する

append メソッドを使用すると、既存のキーに値を追加できます。キーが存在しない場合、append() を呼び出すとキーが作成され、値が設定されます。これは、JavaScript またはレスポンス ヘッダーを使用して実現できます。

  • JavaScript の使用

    既存のキーの値を更新するには、ワークレットの内側または外側から sharedStorage.append() を使用します。

    window.sharedStorage.append('myKey', 'myValue1');
    // Shared Storage: {'myKey': 'myValue1'}
    window.sharedStorage.append('myKey', 'myValue2');
    // Shared Storage: {'myKey': 'myValue1myValue2'}
    window.sharedStorage.append('anotherKey', 'hello');
    // Shared Storage: {'myKey': 'myValue1myValue2', 'anotherKey': 'hello'}
    

    ワークレット内で追加するには:

    sharedStorage.append('myKey', 'myValue1');
    
  • レスポンス ヘッダーの使用

    共有ストレージに値を設定する場合と同様に、レスポンス ヘッダーの Shared-Storage-Write を使用して Key-Value ペアを渡すことができます。

    Shared-Storage-Write : append;key="myKey";value="myValue2"
    

値の一括更新

JavaScript ワークレットの内外から sharedStorage.batchUpdate() を呼び出し、選択したオペレーションを指定するメソッドの順序付き配列を渡すことができます。各メソッド コンストラクタは、set、append、delete、clear の対応する個々のメソッドと同じパラメータを受け取ります。

JavaScript から batchUpdate() を呼び出すか、レスポンス ヘッダーを使用できます。

  • JavaScript の使用

    batchUpdate() で使用できる JavaScript メソッドは次のとおりです。

    • SharedStorageSetMethod(): Key-Value ペアを共有ストレージに書き込みます。
    • SharedStorageAppendMethod(): 共有ストレージ内の既存のキーに値を追加します。キーがまだ存在しない場合は、Key-Value ペアを書き込みます。
    • SharedStorageDeleteMethod(): 共有ストレージから Key-Value ペアを削除します。
    • SharedStorageClearMethod(): 共有ストレージ内のすべてのキーをクリアします。
    sharedStorage.batchUpdate([
    new SharedStorageSetMethod('keyOne', 'valueOne'),
    new SharedStorageAppendMethod('keyTwo', 'valueTwo'),
    new SharedStorageDeleteMethod('keyThree'),
    new SharedStorageClearMethod()
    ]);
    
  • レスポンス ヘッダーの使用

    Shared-Storage-Write : set;key=keyOne;value=valueOne, append;key=keyTwo;value=valueTwo,delete;key=keyThree,clear
    

レスポンス ヘッダーを使用すると、ヘッダー内のすべてのメソッドに対して batchUpdate() が実行されます。

共有ストレージからの読み取り

共有ストレージからの読み取りは、ワークレット内でのみ可能です。

await sharedStorage.get('mykey');

ワークレット モジュールが読み込まれたブラウジング コンテキストのオリジンによって、どの共有ストレージが読み取られるかが決まります。

共有ストレージから削除する

Shared Storage からの削除は、ワークレットの内外の JavaScript を使用するか、delete() を使用してレスポンス ヘッダーを使用することで実行できます。すべてのキーを一度に削除するには、どちらかの clear() を使用します。

  • JavaScript の使用

    ワークレットの外部から共有ストレージから削除するには:

    window.sharedStorage.delete('myKey');
    

    ワークレット内から共有ストレージから削除するには:

    sharedStorage.delete('myKey');
    

    ワークレットの外部からすべてのキーを一度に削除するには:

    window.sharedStorage.clear();
    

    ワークレット内からすべてのキーを一度に削除するには:

    sharedStorage.clear();
    
  • レスポンス ヘッダーの使用

    レスポンス ヘッダーを使用して値を削除するには、レスポンス ヘッダーで Shared-Storage-Write を使用して、削除するキーを渡すこともできます。

    delete;key="myKey"
    

    レスポンス ヘッダーを使用してすべてのキーを削除するには:

    clear;
    

共有ストレージから Protected Audience のインタレスト グループを読み取る

Protected Audience のインタレスト グループは、Shared Storage ワークレットから読み取ることができます。interestGroups() メソッドは、AuctionInterestGroup 属性と GenerateBidInterestGroup 属性を含む StorageInterestGroup オブジェクトの配列を返します。

次の例は、ブラウジング コンテキストのインタレスト グループを読み取る方法と、取得したインタレスト グループに対して実行できる操作を示しています。使用される可能性のある 2 つのオペレーションは、インタレスト グループの数を特定することと、入札回数が最も多いインタレスト グループを特定することです。

async function analyzeInterestGroups() {
  const interestGroups = await interestGroups();
  numIGs = interestGroups.length;
  maxBidCountIG = interestGroups.reduce((max, cur) => { return cur.bidCount > max.bidCount ? cur : max; }, interestGroups[0]);
  console.log("The IG that bid the most has name " + maxBidCountIG.name);
}

ワークレット モジュールが読み込まれたブラウジング コンテキストのオリジンによって、デフォルトで読み取られるインタレスト グループのオリジンが決まります。デフォルトのワークレット オリジンとその変更方法について詳しくは、Shared Storage API のチュートリアルの Shared Storage と Private Aggregation の実行セクションをご覧ください。

オプション

すべての Shared Storage 修飾子メソッドは、最後の引数としてオプションのオプション オブジェクトをサポートしています。

withLock

withLock オプションは省略可能です。指定すると、このオプションは、続行する前に Web Locks API を使用して定義されたリソースのロックを取得するようにメソッドに指示します。ロックをリクエストするときにロック名が渡されます。この名前は、オリジン内の複数のタブ、ワーカー、コード間で使用状況が調整されるリソースを表します。

withLock オプションは、次の Shared Storage 修飾子メソッドで使用できます。

  • set
  • append
  • delete
  • クリア
  • バッチ アップデート

ロックは、JavaScript またはレスポンス ヘッダーを使用して設定できます。

  • JavaScript の使用

    sharedStorage.set('myKey', 'myValue', { withLock: 'myResource' });
    
  • レスポンス ヘッダーの使用

    Shared-Storage-Write : set;key="myKey";value="myValue",options;with_lock="myResource"
    

共有ストレージ ロックはデータ配信元ごとにパーティショニングされます。ロックは、window コンテキストまたは worker コンテキストにあるかどうかにかかわらず、LockManager request() メソッドを使用して取得されたロックとは独立しています。ただし、SharedStorageWorklet コンテキスト内で request() を使用して取得したロックと同じスコープを共有します。

request() メソッドではさまざまな構成オプションを使用できますが、共有ストレージ内で取得されたロックは常に次のデフォルト設定に従います。

  • mode: "exclusive": 同じ名前の他のロックを同時に保持することはできません。
  • steal: false: 同じ名前の既存のロックは、他のリクエストに対応するために解放されません。
  • ifAvailable: false: ロックが使用可能になるまで、リクエストは無期限に待機します。
withLock を使用するタイミング

ロックは、複数のワークレットが同時に実行される可能性があるシナリオ(ページ上の複数のワークレット、または異なるタブの複数のワークレットなど)で、それぞれが同じデータを参照している場合に便利です。このシナリオでは、関連するワークレット コードをロックでラップして、一度に 1 つのワークレットのみがレポートを処理するようにすることをおすすめします。

ロックが役立つもう 1 つの状況は、ワークレットで一緒に読み取る必要があり、状態を同期する必要がある複数のキーがある場合です。その場合は、get 呼び出しをロックでラップし、それらのキーに書き込むときに同じロックを取得するようにしてください。

ロックの順序

ウェブロックの性質上、修飾子メソッドが定義した順序で実行されないことがあります。最初のオペレーションでロックが必要で、遅延が発生した場合、最初のオペレーションが完了する前に 2 番目のオペレーションが開始されることがあります。

例:

// This line might pause until the lock is available.
sharedStorage.set('keyOne', 'valueOne', { withLock: 'resource-lock' });

// This line will run right away, even if the first one is still waiting.
sharedStorage.set('keyOne', 'valueTwo');
複数のキーを変更する例

batchUpdate() を指定した withLock オプションを使用すると、同じロックを取得する他の同時オペレーションとの相互排他が保証されます。batchUpdate()withLock オプションは、バッチ全体にのみ適用できます。バッチ内の個々のメソッド オブジェクトに withLock を適用すると、例外がスローされます。

この例では、ロックを使用して、ワークレット内の読み取りオペレーションと削除オペレーションが同時に実行されるようにし、ワークレット外からの干渉を防いでいます。

次の modify-multiple-keys.js の例では、modify-lock を使用して keyOnekeyTwo の新しい値を設定し、ワークレットから modify-multiple-keys オペレーションを実行します。

// modify-multiple-keys.js
sharedStorage.batchUpdate([
    new SharedStorageSetMethod('keyOne', calculateValueFor('keyOne')),
    new SharedStorageSetMethod('keyTwo', calculateValueFor('keyTwo'))
], { withLock: 'modify-lock' });

const modifyWorklet = await sharedStorage.createWorklet('modify-multiple-keys-worklet.js');
await modifyWorklet.run('modify-multiple-keys');

次に、modify-multiple-keys-worklet.js 内で navigator.locks.request() を使用してロックをリクエストし、必要に応じて鍵の読み取りと変更を行います。

// modify-multiple-keys-worklet.js
class ModifyMultipleKeysOperation {
  async run(data) {
    await navigator.locks.request('modify-lock', async (lock) => {
      const value1 = await sharedStorage.get('keyOne');
      const value2 = await sharedStorage.get('keyTwo');

      // Do something with `value1` and `value2` here.

      await sharedStorage.delete('keyOne');
      await sharedStorage.delete('keyTwo');
    });
  }
}
register('modify-multiple-keys', ModifyMultipleKeysOperation);

コンテキストの切り替え

共有ストレージのデータは、呼び出し元となったブラウジング コンテキストのオリジン(https://example.adtech.com など)に書き込まれます。

<script> タグを使用してサードパーティのコードを読み込むと、コードは埋め込み元のブラウジング コンテキストで実行されます。そのため、サードパーティ コードが sharedStorage.set() を呼び出すと、データはエンベッダーの共有ストレージに書き込まれます。iframe 内にサードパーティ コードを読み込むと、コードは新しいブラウジング コンテキストを受け取り、そのオリジンは iframe のオリジンになります。そのため、iframe から行われた sharedStorage.set() 呼び出しは、iframe オリジンの共有ストレージにデータを保存します。

ファーストパーティ コンテキスト

ファーストパーティ ページに sharedStorage.set() または sharedStorage.delete() を呼び出すサードパーティ JavaScript コードが埋め込まれている場合、Key-Value ペアはファーストパーティ コンテキストに保存されます。

サードパーティの JavaScript が埋め込まれたファーストパーティのページに保存されたデータ。
この図は、サードパーティの JavaScript が埋め込まれたファーストパーティのページに保存されているデータを表しています。

サードパーティのコンテキスト

Key-Value ペアは、iframe を作成し、iframe 内の JavaScript コードで set() または delete() を呼び出すことで、広告テクノロジーまたはサードパーティのコンテキストに保存できます。

広告テクノロジーまたはサードパーティのコンテキストに保存されたデータ。
この図は、広告テクノロジーまたはサードパーティのコンテキストに保存されたデータを表しています。

Private Aggregation API

Shared Storage に保存されている集計可能なデータを測定するには、Private Aggregation API を使用します。

レポートを作成するには、バケットと値を使用してワークレット内で contributeToHistogram() を呼び出します。バケットは符号なし 128 ビット整数で表され、BigInt として関数に渡す必要があります。値は正の整数です。

プライバシーを保護するため、バケットと値を含むレポートのペイロードは転送中に暗号化され、集計サービスでのみ復号と集計が可能です。

ブラウザは、サイトが出力クエリに提供できる貢献度も制限します。具体的には、貢献予算は、特定のブラウザの特定の期間における単一サイトからのすべてのレポートの合計を、すべてのバケットにわたって制限します。現在の予算を超過すると、レポートは生成されません。

privateAggregation.contributeToHistogram({
  bucket: BigInt(myBucket),
  value: parseInt(myBucketValue)
});

Shared Storage と Private Aggregation の実行

デフォルトでは、createWorklet() で共有ストレージを使用する場合、データ パーティションのオリジンは、ワークレット スクリプト自体のオリジンではなく、呼び出し元のブラウジング コンテキストのオリジンになります。

デフォルトの動作を変更するには、createWorklet を呼び出すときに dataOrigin プロパティを設定します。

  • dataOrigin: "context-origin": (デフォルト)データは、呼び出し元のブラウジング コンテキストのオリジンの共有ストレージに保存されます。
  • dataOrigin: "script-origin": データは、ワークレット スクリプトのオリジンの共有ストレージに保存されます。このモードを有効にするには、オプトインが必要です。
  • dataOrigin: "https://custom-data-origin.example": データはカスタムデータ オリジンの共有ストレージに保存されます。このモードを有効にするにはオプトインが必要であり、カスタムデータ オリジン オーナーの同意が必要です。詳しくは、カスタムデータ オリジンをご覧ください。
sharedStorage.createWorklet(scriptUrl, {dataOrigin: "script-origin"});

オプトインするには、"script-origin" またはカスタム オリジンを使用する場合、スクリプト エンドポイントがヘッダー Shared-Storage-Cross-Origin-Worklet-Allowed で応答する必要があります。クロスオリジン リクエストの場合は、CORS も有効にする必要があります。

Shared-Storage-Cross-Origin-Worklet-Allowed : ?1
Access-Control-Allow-Origin: *

サードパーティの iframe を使用してクロスオリジン スクリプトを実行することもできます。この場合、共有ストレージ アクションはサードパーティのブラウジング コンテキストに配置されます。

クロスオリジン iframe の使用

共有ストレージ ワークレットを呼び出すには、iframe が必要です。

広告の iframe で、addModule() を呼び出してワークレット モジュールを読み込みます。sharedStorageWorklet.js ワークレット ファイルに登録されているメソッドを同じ広告 iframe JavaScript で実行するには、sharedStorage.run() を呼び出します。

const sharedStorageWorklet = await window.sharedStorage.createWorklet(
  'https://any-origin.example/modules/sharedStorageWorklet.js'
);
await sharedStorageWorklet.run('shared-storage-report', {
  data: { campaignId: '1234' },
});

ワークレット スクリプトでは、非同期 run メソッドを含むクラスを作成し、広告の iframe で実行されるように register する必要があります。sharedStorageWorklet.js 内:

class SharedStorageReportOperation {
  async run(data) {
    // Other code goes here.
    bucket = getBucket(...);
    value = getValue(...);
    privateAggregation.contributeToHistogram({
      bucket,
      value
    });
  }
}
register('shared-storage-report', SharedStorageReportOperation);

クロスオリジン リクエストの使用

Shared Storage と Private Aggregation を使用すると、クロスオリジン iframe を必要とせずにクロスオリジン ワークレットを作成できます。

ファーストパーティ ページは、クロスオリジン JavaScript エンドポイントへの createWorklet() 呼び出しを呼び出すこともできます。ワークレットを作成するときに、ワークレットのデータ パーティションのオリジンをスクリプトのオリジンに設定する必要があります。

async function crossOriginCall() {
  const privateAggregationWorklet = await sharedStorage.createWorklet(
    'https://cross-origin.example/js/worklet.js',
    { dataOrigin: 'script-origin' }
  );
  await privateAggregationWorklet.run('pa-worklet');
}
crossOriginCall();

クロスオリジン JavaScript エンドポイントは、ヘッダー Shared-Storage-Cross-Origin-Worklet-Allowed で応答し、リクエストで CORS が有効になっていることを通知する必要があります。

Shared-Storage-Cross-Origin-Worklet-Allowed : ?1

createWorklet() を使用して作成された Worklet には、selectURLrun() があります。addModule() はご利用いただけません。

class CrossOriginWorklet {
  async run(data){
    // Other code goes here.
    bucket = getBucket(...);
    value = getValue(...);
    privateAggregation.contributeToHistogram({
      bucket,
      value
    });
  }
}

カスタム データ取得元

dataOrigin が有効なオリジンに設定されている場合、dataOrigin の所有者は、ワークレット スクリプトのオリジンをリストした JSON ファイルをパス /.well-known/shared-storage/trusted-origins でホストすることで、その dataOrigin の Shared Storage の処理に同意する必要があります。ファイルは、キー scriptOrigincontextOrigin を含むオブジェクトの配列にする必要があります。これらのキーの値は、文字列または文字列の配列のいずれかになります。

次の情報を使用して trusted-origins ファイルを作成します。

  • 発信者のコンテキスト
  • ワークレット スクリプトのオリジンと URL
  • データの取得元と所有者

次の表は、この情報に基づいて trusted-origins ファイルを構築する方法を示しています。

発信者のコンテキスト ワークレット スクリプトの URL データ取得元 データオーナー データ送信元の所有者の trusted-origins JSON ファイル
https://publisher.example https://publisher.example/script.js context-origin https://publisher.example JSON は不要
https://publisher.example https://ad.example/script.js script-origin https://ad.example JSON は不要
https://publisher.example https://cdn-ad.example/script.js https://ad.example https://ad.example
[{
  "scriptOrigin": "https://cdn-ad.example",
  "contextOrigin": "https://publisher.example"
}]
      
任意の呼び出し元 https://cdn-ad.example/script.js https://ad.example https://ad.example
[{
  "scriptOrigin": "https://cdn-ad.example",
  "contextOrigin": "*"
}]
      
https://publisher-a.example、または https://publisher-b.example https://cdn-ad.example/script.js https://ad.example https://ad.example
[{
  "scriptOrigin": "https://cdn-ad.example",
  "contextOrigin": [
      "https://publisher-a.example",
      "https://publisher-b.example"
  ]
}]
      
https://publisher.example https://cdn-a-ad.example/script.js、または https://cdn-b-ad.example/script.js https://ad.example https://ad.example
[{
  "scriptOrigin": [
    "https://cdn-a-ad.example",
    "https://cdn-b-ad.example"
  ],
  "contextOrigin": "https://publisher.example"
}]
      

たとえば、次の JSON は https://custom-data-origin.example/.well-known/shared-storage/trusted-origins でホストされ、https://custom-data-origin.example オリジンの共有ストレージ データのすべての許可されたプロセッサを組み合わせることができます。

[
  {
    "scriptOrigin": "https://script-origin.a.example",
    "contextOrigin": "https://context-origin.a.example"
  },
  {
    "scriptOrigin": "https://script-origin.b.example",
    "contextOrigin": [
      "https://context-origin.a.example",
      "https://context-origin.b.example"
    ]
}]

次のステップ

以下のページでは、Shared Storage API と Private Aggregation API の重要な側面について説明します。

API を理解したら、レポートの収集を開始できます。レポートは、リクエストの本文の JSON として、次のエンドポイントに POST リクエストとして送信されます。

  • デバッグ レポート - context-origin/.well-known/private-aggregation/debug/report-shared-storage
  • レポート - context-origin/.well-known/private-aggregation/report-shared-storage

レポートが収集されたら、ローカルテストツールを使用してテストするか、集計サービスの信頼できる実行環境を設定して集計レポートを取得できます。

フィードバックをお寄せください

API とドキュメントに関するフィードバックは、GitHub で共有できます。