TopicsAPIって結局どうすれば利用できるのか

# はじめに
こんにちは、株式会社インティメート・マージャーの @eknis です。
TopicsAPIを触る機会があったのですがドキュメントから読み取りづらい部分もあり、
- とりあえず試したいという方
- ちゃんと設定して運用したい方
に向けてざっくりまとめました。

# TopicsAPI とは？
TopicsAPI は、ブラウザ内でユーザーの関心に基づくトピックを抽出する仕組みを提供するAPIです。ユーザーのプライバシーを尊重しながら、関連するトピックを特定してパーソナライズされたコンテンツや広告を提供するために使用されます。
https://developers.google.com/privacy-sandbox/private-advertising/topics

# なぜ今書くのか
2022年に発表されたTopicsAPIですが徐々に環境が整い、実際に利用がされてきているからです。
具体的な要因としては
- Model, Taxonomyのversionが更新されており最適化されてきた
- Web 向け Header Bidding ライブラリである[Prebid](https://docs.prebid.org/dev-docs/modules/topicsFpdModule.html)のModuleが運用され出したこと

などがあります。

# 利用条件、設定
## 動くブラウザ
TopicsAPI を利用するには、以下の条件を満たす必要があります：

対応ブラウザ: TopicsAPI は、対応するブラウザ（例: Google Chrome）の最新バージョンで利用可能です。
HTTPS: サイトが HTTPS を使用していること。
ブラウザ設定: ブラウザが TopicsAPI の利用を許可している必要があります。

:::note info
Chromiumベースのブラウザが対応しておりchromeの他にEdge, Opera, SamsungInternetなどが[TopicsAPI](https://developer.mozilla.org/en-US/docs/Web/API/Topics_API)に対応しています
:::

## TOPICSを見てみたい、共有してもらいたい、登録まで必要ないパターン
サイトで検出されたtopicを共有できます。
その場合 `fetch` を利用することができます。
TOPICSの利用登録をしているDSPなどから共有されたurlを設定するだけです。

:::note warn
XHR リクエストにトピックヘッダーを含めることは一時的にのみ利用可能であり、サポートは今後削除される予定です。
:::

実装は簡単で指定されたurlに対してfetchを行うだけですが
`browsingTopics` を必ず設定してください。

```javascript
const response = await fetch("partner-ssp.example", {
 browsingTopics: true
});
```


## TOPICSの利用登録を行いたいパターン
取得できるようにするには登録が必要になります。
https://developers.google.com/privacy-sandbox/blog/announce-enrollment-privacy-sandbox?hl=ja
このあたりからフォームで登録を行います。

その際サイトの設定が必要で

ここでいうサイトとは
![image (40).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188192/ebc075ab-d627-4131-569d-df05f89b8baf.png)


https://web.dev/static/articles/same-site-same-origin/image/site-tld1-ae5ebbc587fbe.png?hl=ja

`.com` や `.org` などの[トップレベル ドメイン（TLD）](https://developer.mozilla.org/docs/Glossary/TLD)は、[ルートゾーン データベース](https://www.iana.org/domains/root/db)にリストされています。上記の例では、「サイト」は、[スキーム](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web#Scheme_or_protocol)、[TLD](https://developer.mozilla.org/docs/Glossary/TLD)、およびその直前のドメインの部分（ここでは TLD+1）を組み合わせたものです。たとえば、URL が `https://www.example.com:443/foo` の場合、「サイト」は `https://example.com` です。

登録が承認されると指定したサイトで利用可能になります。

https://developers.google.com/privacy-sandbox/blog/announce-enrollment-privacy-sandbox?hl=ja

https://github.com/privacysandbox/attestation/blob/main/how-to-enroll.md

### 実際のForm

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188192/61fcf33d-5c3d-a880-7cd7-0f6691d84826.png)
8ページあります

### 基本的なフロー
TopicsAPI は以下の手順で利用します：

##### API へのアクセス
TopicsAPI は navigator オブジェクトを通じて利用します。

```javascript
if ('browsingTopics' in navigator) {
    navigator.browsingTopics().then((topics) => {
        console.log('User topics:', topics);
    }).catch((error) => {
        console.error('Error fetching topics:', error);
    });
} else {
    console.log('TopicsAPI is not supported in this browser.');
}
```
##### トピックの取得
TopicsAPI は、ユーザーが訪問したサイトやその内容に基づいて、関連するトピックを取得します。返されるトピックは一般的なカテゴリ名（例: スポーツ、テクノロジー）で、ユーザー個人を特定しません。

取得されたデータは以下の形式です：

```javascript
[
    { topic: 1, taxonomyVersion: 1 },
    { topic: 23, taxonomyVersion: 1 }
]
```
topic: トピックを表すID。
taxonomyVersion: 使用されるトピック分類のバージョン。
##### データの活用
取得したトピック情報は、以下のような用途に利用できます：

パーソナライズされた広告の表示
サイトのコンテンツ最適化
関連製品の提案
##### 注意点と制限
プライバシー: トピックはユーザーが訪問したサイトを特定しない形で提供されます。
制限: トピックの数や期間には制限があります（例: 最大3週間分のトピック）。
対応ブラウザ依存: 現在 TopicsAPI をサポートしているのは一部のブラウザのみです。
# 実践例
おおまかに二種類取得方法があり
- JavaScriptAPIでTopicsにアクセスする
- Header情報から取得する
2つのアプローチがあります。

## JavaScriptAPIでTopicsにアクセスする

別ドメインサイトでJavaScriptAPIを利用するには登録したサイト上で実行する必要があるためiframeを利用します。
```
<iframe src="https://example.com" browsingtopics></iframe>
```
:::note info
browsingtopicsを付与することでHeaderから取得する事もできます。
:::
iframe内で実行する内容例

```javascript
async function fetchUserTopics() {
    if (!('browsingTopics' in navigator)) {
        console.error('TopicsAPI is not supported in this browser.');
        return;
    }

    try {
        const topics = await navigator.browsingTopics();
        console.log('Retrieved topics:', topics);
        // 広告用のAPIにトピックを送信
        sendTopicsToAdServer(topics);
    } catch (error) {
        console.error('Error retrieving topics:', error);
    }
}

function sendTopicsToAdServer(topics) {
    // サーバーにトピック情報を送信する処理
    fetch('/ad-server', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ topics }),
    }).then(response => response.json())
}

fetchUserTopics();
```
このようにすることでtopframeのサイトからTopicsが記録されます。


## Header情報から取得する
ポイントは2つです。
- `browsingTopics: true`でリクエストすることによってHeaderにTopicsを付与します
- `Observe-Browsing-Topics: ?1` でレスポンスすることで観測済みとしてマークします


```javascript
fetch('<topics_caller_eTLD+1>', { browsingTopics: true })
  .then((response) => {
    // topicや付帯情報の返却が想定
  }
);
```
こちらの方法ではiframeを使わずtopFrameで実行可能なためアプリwebview環境などでも利用しやすいかもしれません。

# 最後に
最後まで読んでくださり、ありがとうございました！

明日以降の記事もお楽しみに！
https://qiita.com/advent-calendar/2024/intimatemerger