【Google Analytics 4】Reporting API v4 を Golang で使ってみる

# はじめに
株式会社データインサイトの山元です。
弊社ではポイ活アプリや開業準備支援アプリなど複数のプロダクトを展開しており
ユーザーの利用状況を見て、次のアクションを考え、アプリの改善に繋げています。

会社の中だけで KPI を共有する分には、Firebase だけで事足りるのですが
パートナー企業等の外部ユーザーに主要 KPI をリアルタイムで連携する要件があり
弊社と外部ユーザーとの間で使える管理アプリを構築することになりました。

今回は、バックエンドのサーバー言語が Golang のため、
Golang で Google Analytics 4 のAPIを使ってみます。

# Google Analytics 4 とは
まず Google Analytics には、「Universal Analytics（GA3）」と「Google Analytics 4」があります。それぞれの違いのついては、ググれば大量に出てきますが、ざっくり言うと...

■ Universal Analytics（UA または GA3）
・UI／機能ともに各所で慣れ親しまれていて、世間一般的なGAと言えばこれ
・Webサイトのページビュー／GTMと組み合わせた各種イベントの計測がメイン
・計測対象がデバイス × ブラウザの前提なので、Cookieをもとにした計測となる

■ Google Analytics 4（GA4）
・UAの進化版で、まだあまり世の中に浸透していない
・Webだけでなくアプリの計測も可能（Firebase で連携するユースケースが一般的）
・計測対象はユーザーがサイトやアプリで実行したイベントがベースとなる

WebだとUAの方が使いやすいですが、アプリのイベント計測には GA4が適しています。
そして2023年7月1日UAのサポートは終了するので、いずれはGA4に移行せざるを得ません。

https://support.google.com/analytics/answer/11583528?hl=ja

> 2023 年 7 月 1 日をもって、標準のユニバーサル アナリティクス プロパティにおける新しいヒットの処理は停止されます。現在ユニバーサル アナリティクスをご利用のお客様には、Google アナリティクス 4 を使用するための準備をしていただくことをおすすめします。

# Google Analytics Reporting API v4 とは
従来よりUA用のAPIはありますが、GA4のAPIもあります。

https://developers.google.com/analytics/devguides/reporting/data/v1

これを使うと、GA4で計測された数字をAPIで呼び出すことが出来ます。
Google 公式サイトによるとまだβ版なので今後仕様変更はあるかもしれませんがおそらく大きく変わらないのと、そもそも一般ユーザー向けにGA4で取れる数字を見せるユースケースはあんまりないと思うので製品版で使用しても差し支えないと思います。（自己責任でお願いします...！）

それではようやく本題です。
ここから、Golang で稼働するサーバーで Reporting API v4を呼べるようにします。

# 1. GCP で専用のサービスアカウントを作る
Google サービスのAPIを外部のプログラムからコールする際には、Google のサービスアカウントでOAuth2認証が必要になるため、まずはサービスアカウントを作成します。

以下手順はGCPアカウントでプロジェクトを作成した前提で進めます。
GCPにログインして対象のプロジェクトを選択したうえで、「IAMと管理」>「サービスアカウント」から「+サービスアカウントを作成」をクリックします。サービスアカウント名、サービスアカウントID、サービスアカウントの説明の入力を求められますが、ここは任意で大丈夫です。
「完了」を押すとサービスアカウントの管理画面に戻るので、作成したサービスアカウントがあることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528515/d35849fc-57a7-bed2-9a8c-cc2c4c778a12.png)

作成したサービスアカウントの詳細ページに行き、「キー」のタブを選択します。「鍵を追加」というドロップダウンリストがあるので、「新しい鍵を作成」を選択します。
以下のようなダイアログが表示されるので、キーのタイプを「JSON」にして「作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528515/1b2ca9c8-87d6-3536-326a-448026224e65.png)

その後、自動で鍵ファイルがJSON形式でダウンロードされるので大事に保存してください。（作成したJSONファイルは二度とダウンロード出来ません）
後の手順で使用しますので、ファイル名を「credentials.json」にしておいてください。

# 2. GA4とサービスアカウントを連携する
APIで取得したいGA4のプロパティを開きます。
「管理」>「アカウントのアクセス権」で「＋」>「ユーザーを追加」を押してメールアドレス欄に、先程ダウンロードした JSONファイル内の「client_email」にあるメールアドレスを入力します。標準の役割の箇所はユースケースによりますが、「管理者」で設定します。この状態で「追加」を押して、ユーザーを追加すると、作成したサービスアカウントからGA4へのアクセスが許可されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528515/2bd5630b-bc67-644a-0f36-6882cb59af5c.png)


# 3. GolangでAPIをコールしてみる
APIをコールするためには、GCPで「Google Analytics Data API」を「有効」にする必要があります。
（以下のリンク先から有効に出来ます）
https://console.cloud.google.com/apis/library/analyticsdata.googleapis.com

その後のおおまかな手順は公式を確認いただくと正確です、
と言いたいところですが、なんとGolang 用のチュートリアルがありません。

https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart-client-libraries

以下のライブラリを使用するところまでは記載されていますが、具体的なコールの方法が明記されていません。
```
go get google.golang.org/genproto/googleapis/analytics/data/v1beta
```
環境変数「GOOGLE_APPLICATION_CREDENTIALS」に「credentials.json」のファイルパスを通した上で、こんな感じで Python等のコードチュートリアルからGoに変換して書いてみるものの...
```go:analytics.go（動かない例）
import (
	ga "google.golang.org/genproto/googleapis/analytics/data/v1beta"
	"google.golang.org/grpc"
}

func GetAnalytics() (*ga.RunReportResponse, error) {
	cc := &grpc.ClientConn{}
	client := ga.NewBetaAnalyticsDataClient(cc)
	ctx := context.Background()
	runReportRequest := &ga.RunReportRequest{
		Property: "properties/XXXXXXXXX", // XXXXXXXXX の部分に property id が入る
		DateRanges: []*ga.DateRange{
			{StartDate: "2022-03-30", EndDate: "2022-04-30"},
		},
		Dimensions: []*ga.Dimension{
			{Name: "city"},
		},
		Metrics: []*ga.Metric{
			{Name: "active1DayUsers"},
			{Name: "active7DayUsers"},
			{Name: "active28DayUsers"},
		},
	}
	res, err := client.RunReport(ctx, runReportRequest)
	if err != nil {
		return nil, err
	}
    return res, nil
}
```

サービスアカウントの認証情報がリクエストに入っていないからか、nil pointer エラーが出ます。
ちなみに property id は、計測対象の Google Analytics 4 のプロパティをご利用ください。

```
panic: runtime error: invalid memory address or nil pointer dereference
```

サービスアカウントの自動検出は「cloud.google.com/go」から始まるパッケージ名のみが対象のようで、手動で環境変数を設定しても今回のパッケージでは検出されません。サービスアカウント認証については公式サイトをご確認ください。

https://cloud.google.com/docs/authentication/production


結論、別のパッケージを使ってサービスアカウント認証をすれば正常に動きました。

```go:analytics.go（動く例）
import (
	ga "google.golang.org/api/analyticsdata/v1beta"
	"google.golang.org/api/option"
}
func GetAnalytics() (*ga.RunReportResponse, error) {
	ctx := context.Background()
	client, err := ga.NewService(ctx, option.WithCredentialsFile("./credentials.json"))
	if err != nil {
		return nil, err
	}

	runReportRequest := &ga.RunReportRequest{
		DateRanges: []*ga.DateRange{
			{StartDate: "2022-03-30", EndDate: "2022-04-30"},
		},
		Dimensions: []*ga.Dimension{
			{Name: "city"},
		},
		Metrics: []*ga.Metric{
			{Name: "active1DayUsers"},
			{Name: "active7DayUsers"},
			{Name: "active28DayUsers"},
		},
	}
	res, err := client.Properties.RunReport("properties/XXXXXXXXX", runReportRequest).Do() // XXXXXXXXX の部分に property id が入る
	if err != nil {
		return nil, err
	}

	return res, nil
}
```

今回セットした DimensionsとMetricsでは、以下のようなレスポンスが返ってこれば成功です。

```
{
    "dimensionHeaders": [
        {
            "name": "city"
        }
    ],
    "kind": "analyticsData#runReport",
    "metadata": {
        "currencyCode": "JPY",
        "timeZone": "Asia/Tokyo"
    },
    "metricHeaders": [
        {
            "name": "active1DayUsers",
            "type": "TYPE_INTEGER"
        },
        {
            "name": "active7DayUsers",
            "type": "TYPE_INTEGER"
        },
        {
            "name": "active28DayUsers",
            "type": "TYPE_INTEGER"
        }
    ],
    "rowCount": 1,
    "rows": [
        {
            "dimensionValues": [
                {
                    "value": "Chuo City"
                }
            ],
            "metricValues": [
                {
                    "value": "1000"
                },
                {
                    "value": "7000"
                },
                {
                    "value": "28000"
                }
            ]
        },
    ]
}
```

# まとめ
以上、Golangで Reporting API v4 を呼ぶ方法でした。
とにかく GA4周りの情報が無さすぎて、中々苦労しました...。

Stack Overflow でも数ヶ月前から同じ悩みが起票されていて、しばらく謎に包まれていましたが、数日前に解決策が投稿されていました。（当記事と同じです）

https://stackoverflow.com/questions/70694362/how-to-use-google-analytics-data-api-v1-with-golang

Google 公式チュートリアルで紹介されたパッケージに頼らずにコールする方法を模索する過程で、自前で Bearer Token作成コードを作って以下URLからリクエストする方法も試して動作確認しました。

```
https://content-analyticsdata.googleapis.com/v1beta/properties/XXXXXXXXX:runReport
// XXXXXXXXX の部分に property id が入る
```

そちらの方法もまとまったものは見当たらなかったので、また別記事で紹介しますね。需要があるかは謎ですが、Google サービスのOAuth認証について詳しくなれるのと、言語に依存せずに使えるところはメリットかもしれません。また、今回のAPIでリクエストに入れる Dimensions や Metrics などのAPI仕様や、結局このAPIを使って何ができるかについても今後紹介していこうと思います。

# さいごに
最後までお読みいただきありがとうございました！
Data Insight Inc.では "地図×データで新しい未来をつくる" ことを目指して、
様々なデータとテクノロジーを活かした取り組みを進めています。
さらなる事業拡大のためにデータサイエンティスト、エンジニア、デザイナーの仲間を募集中です。
ご興味いただけた方は、遠慮なくご連絡いただければ嬉しいです！

https://datainsight.jp/recruit