簡易ECサイトにPixelタグとCAPIを導入してみました

## tl;dr
* 簡易のECサイトにMetaのPixelとCAPIを導入してみました
* Pixelと詳細マッチングがブラウザ側での実装に対して、CAPIはサーバー側での実装が必要となるため根本的に別物でした
* PixelとCAPI両方を実装する場合、`Event ID`の実装がほぼ必須です

## What I did
### 手順
1. ECサイトの構成について確認
1. Metaの広告マネージャーからPixelを作成。CAPI実装用に`API_token`を発行
1. 購入完了した顧客情報を`stripe_api`にて取得
1. 購入完了ページにてCAPI実装
1. Pixelを各Webページに実装
**今回はテストですが、実際にはプライバシポリシーや顧客情報取扱いについての確認が最初になると思います。**


#### サイト構成について
現在こんな感じです
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386347/c1500bbb-f2d9-b5ca-e00d-a7d911303a27.png)

実装後イメージ
手動詳細マッチングを実装する際はPixelに追加実装することになるが、今回は割愛
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386347/adc76028-a2f3-03ec-3806-f12b67eb5de6.png)

#### Pixelを作成。CAPI実装用に`API_token`を発行
こちらはMetaの広告管理画面から発行。以下みたいなものをメモしておきます。
Pixel ID: 123456789
API_token:abcdefghijk....

#### `stripe_api`から顧客情報を取得
前提
今回CAPIは、顧客の購入時のイベントを”Purchase”として導入します。Pixelであれば`thanks`ページにタグを埋めれば終わりですが、CAPIの場合はサーバーから送る必要があります。今回、決済に`stripe`を使用しているため、流れとしては *顧客が決済完了した場合、決済データが`stripe`のDBに記録され、`thanks`のurlにリダイレクトされる。* となります
そのため、以下の2点が必要です。
1. 決済成功時に`stripe`のDBから決済データを取得
1. 顧客情報と決済情報を取得し、CAPIとして送信

```python stripe_get_data.py
def get_billing_data():
    data = stripe.Charge.list(limit=1)["data"]

    email = data[0]["billing_details"]["email"]
    hashed_email = hash(email)
    id = data[0]["id"]
```
今回は、顧客データとして`email`、`Event ID`用に購入IDを取得
今回はテストのため、直近のデータ1つを取得していますが、実際にはある程度の量を取得し、ユニークな値を`order.db`などに保存するのが良いと思われます。
stripeのcheckoutについては詳細[こちら](https://stripe.com/docs/payments/checkout/how-checkout-works?locale=ja-JP
)を参照

#### 購入完了ページにCAPI実装
続いて、CAPI送信用のコードを実装。今回はテスト用に必須パラメータ、顧客情報として`email`、`Event ID`のみを実装。テストのため`POST`先のurlは直書きしてしまっていますが、実際にはMeta側で用意されている`business SDK`を使ってリクエストを作成するのが良いかと思います。
(参照: Using API [developer page](https://developers.facebook.com/docs/marketing-api/conversions-api/using-the-api))

```python capi_test.py
CAPI_access_token = os.getenv('CAPI_ACCESS_TOKEN')
pixel_id = os.getenv('PIXEL_ID')

def send_conversion_api(email, event_id):
    url = 'https://graph.facebook.com/{VERSION}/{PIXEL_ID}/events?access_token={TOKEN}'.format(VERSION = v16.0, PIXEL_ID = pixel_id, TOKEN = CAPI_access_token)

    obj = {
        "data": [
            {
                "event_name": "Purchase",
                "event_time": int(time.time()),
                "event_id": event_id,
                "action_source": "website",
                "user_data": {
                    "em": [
                        email
                    ],
                },
                "custom_data": {
                    "currency": "SGD",
                    "value": "11.0"
                }
            }
        ],
    }
    x = requests.post(url, json = obj)

def hash(string):
    return hashlib.sha256(string.encode('utf-8')).hexdigest()
```
実際に送信してみると、`response success`が帰ってくる。15−20分くらいするとMetaのEvent managerにもデータが反映されていました。
![Screenshot 2023-02-28 at 12.51.17 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386347/5faef841-6055-ebfd-2ae1-38b10c15c453.png)

#### Pixelを各Webページに実装
最後にPixelを各ページに実装。こちら`html`にタグを貼り付けていくだけ。Pixelはベースタグとイベントタグの2つがあり、ベースタグ > イベントタグの順番で設定しないとうまく反応しません。
```html example.html
    <!-- Meta Pixel Code -->
    <script>
        !function (f, b, e, v, n, t, s) {
            if (f.fbq) return; n = f.fbq = function () {
                n.callMethod ?
                n.callMethod.apply(n, arguments) : n.queue.push(arguments)
            };
            if (!f._fbq) f._fbq = n; n.push = n; n.loaded = !0; n.version = '2.0';
            n.queue = []; t = b.createElement(e); t.async = !0;
            t.src = v; s = b.getElementsByTagName(e)[0];
            s.parentNode.insertBefore(t, s)
        }(window, document, 'script',
            'https://connect.facebook.net/en_US/fbevents.js');
        fbq('init', '<PIXEL ID>');
        fbq('track', 'PageView');
    </script>
    <!-- End Meta Pixel Code -->

    <!-- Meta event tag -->
  <script>
    fbq('track', 'Purchase');
  </script>

```
ベースコードは`head`の一番下、イベントタグは`body`の中に設置。
今回はカート追加のみ、`onclick()``にてボタンクリックで設定

#### 最後に
PixelとCAPI両方が反応していることを確認し、実装完了

## Ref
* Meta conversion API
https://developers.facebook.com/docs/marketing-api/conversions-api/

* Stripe checkout
https://stripe.com/docs/payments/checkout/how-checkout-works?locale=ja-JP