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

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

対象ユーザー: 広告テクノロジーおよび測定プロバイダ。

Shared Storage API

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

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

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

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

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

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

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

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

    JavaScript と同様に、レスポンス ヘッダーを使用して実行できる機能は、共有ストレージの値の設定、追加、削除などの特定の関数に限られます。レスポンス ヘッダーで共有ストレージを操作するには、リクエスト ヘッダーに 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";
      

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

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

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

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

同じページの読み込みで同じキーを使用して Shared Storage に複数回アクセスすると、キーの値が上書きされます。キーで以前の値を保持する必要がある場合は、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"
    

値の一括更新

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

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

  • JavaScript を使用している場合

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

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

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

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

共有ストレージから読み取ることができるのは、ワークレット内からのみです。

await sharedStorage.get('mykey');

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

共有ストレージからの削除

共有ストレージからの削除は、ワークレットの内外から 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 のインタレスト グループは、共有ストレージ ワークレットから読み取ることができます。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 の実行」セクションをご覧ください。

オプション

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

withLock

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

withLock オプションは、次の共有ストレージ修飾子メソッドで使用できます。

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

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

  • JavaScript を使用している場合

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

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

Shared Storage ロックは、データの送信元によってパーティショニングされます。ロックは、window コンテキストか worker コンテキストかにかかわらず、LockManagerrequest() メソッドを使用して取得されたロックとは独立しています。ただし、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');
複数のキーを変更する例

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

次の 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 が埋め込まれたファースト パーティ ページに保存されているデータ。

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

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)
});

共有ストレージと非公開集計の実行

共有ストレージからデータにアクセスするには、ワークレットを作成する必要があります。これを行うには、ワークレットの URL を指定して createWorklet() を呼び出します。デフォルトでは、createWorklet() で共有ストレージを使用する場合、データ パーティションのオリジンは、ワークレット スクリプト自体のオリジンではなく、呼び出し元のブラウジング コンテキストのオリジンになります。

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

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

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

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

クロスオリジン 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 メソッドを持つクラスを作成し、register して広告の iframe で実行する必要があります。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() を使用して作成されたワークレットには、selectURLrun() があります。addModule() は使用できません。

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

次のステップ

以降のページでは、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 で共有できます。