tech.sinayaka.com

PythonからGA4 Data APIにアクセスするまでが長かった

2026-06-03
2026-07-18
4分
657語
Web技術 PythonGA4Firebase
目次

    iOSアプリのFirebase Analyticsデータを定期的にPythonで取得したかった。GA4 Data APIを叩けばいいだけの話なのに、認証で半日溶かした。

    何がダメだったか

    GA4 Data APIには analytics.readonly スコープが必要。これが曲者で、手元の認証情報のどれも持っていなかった。

    Firebase CLI トークン → ❌

    token = json.loads(Path.home().joinpath('.config/configstore/firebase-tools.json').read_text())['tokens']['access_token']
    # → 401

    Firebase CLIのトークンにはFirebase系のスコープしかない。GA4は別。

    gcloud トークン → ❌

    TOKEN=$(gcloud auth print-access-token)
    curl -H "Authorization: Bearer $TOKEN" https://analyticsdata.googleapis.com/...
    # → 403 ACCESS_TOKEN_SCOPE_INSUFFICIENT

    gcloudのトークンは cloud-platform スコープのみ。

    gcloud auth application-default login --scopes=... → ❌

    gcloud auth application-default login \
      --scopes=https://www.googleapis.com/auth/analytics.readonly,...
    # → Googleにブロックされる

    gcloudのOAuthクライアントに analytics.readonly が登録されていないのでそもそもリクエストできない。

    サービスアカウント → ほぼ❌

    サービスアカウントは作れるし、キーも生成できる。でもGA4プロパティへのアクセス権を付与するには、GAのUIかAnalytics Admin APIが必要。

    UIからサービスアカウントのメールアドレスを追加しようとしたら「Googleアカウントと一致しません」と弾かれた。サービスアカウントのメールはGoogleアカウントではないのでGAのUIから直接追加できない。Analytics Admin APIで追加しようとしたら、それにも analytics.manage.users スコープが必要で…という無限ループ。

    解決策: OAuth 2.0 Playground

    一番手軽だったのが Google OAuth 2.0 Playground

    1. 左のリストから Google Analytics Data API v1analytics.readonly を選択
    2. Authorize → Googleアカウントでログイン
    3. Exchange authorization code for tokens
    4. access_tokenrefresh_token を取得

    ただしPlaygroundのOAuthクライアントは独自のものなので、refresh_token を使い回すには同じクライアントが必要。別のクライアントでは使えない。

    永続化: 自前OAuthクライアントを作る

    GCP Console で OAuth 2.0クライアントID(デスクトップアプリ)を作成して client_secret.json をダウンロード。その後ローカルでブラウザ認証フローを走らせる。

    from google_auth_oauthlib.flow import InstalledAppFlow
    
    SCOPES = ["https://www.googleapis.com/auth/analytics.readonly"]
    flow = InstalledAppFlow.from_client_secrets_file("client_secret.json", SCOPES)
    creds = flow.run_local_server(port=8080, prompt='consent')
    
    # refresh_tokenを保存しておけば次回以降はブラウザ不要
    import json
    json.dump({
        "refresh_token": creds.refresh_token,
        "client_id": creds.client_id,
        "client_secret": creds.client_secret,
        "token_uri": creds.token_uri,
        "scopes": list(creds.scopes)
    }, open("~/.ga4-credentials.json", "w"))

    ただし、GCPプロジェクトで Google Analytics Data API を有効化していないと動かない。

    gcloud services enable analyticsdata.googleapis.com --project=YOUR_PROJECT

    毎回使う時のコード

    from google.analytics.data_v1beta import BetaAnalyticsDataClient
    from google.analytics.data_v1beta.types import RunReportRequest, DateRange, Metric
    from google.oauth2.credentials import Credentials
    from google.auth.transport.requests import Request
    import json, pathlib
    
    c = json.loads(pathlib.Path.home().joinpath('.ga4-credentials.json').read_text())
    creds = Credentials(
        token=None,
        refresh_token=c['refresh_token'],
        token_uri=c['token_uri'],
        client_id=c['client_id'],
        client_secret=c['client_secret'],
        scopes=c['scopes']
    )
    creds.refresh(Request())  # access_tokenを自動更新
    client = BetaAnalyticsDataClient(credentials=creds)
    
    req = RunReportRequest(
        property="properties/YOUR_PROPERTY_ID",
        date_ranges=[DateRange(start_date="30daysAgo", end_date="today")],
        metrics=[Metric(name="activeUsers")]
    )
    resp = client.run_report(req)
    print(resp.rows[0].metric_values[0].value)

    まとめ

    方法結果理由
    Firebase CLIトークンanalyticsスコープなし
    gcloudトークンanalyticsスコープなし
    gcloud —scopesGoogleにブロックされる
    サービスアカウントGAのUI/APIから権限付与が別途必要
    OAuth Playground一時的なアクセスに使える
    自前OAuthクライアントrefresh_tokenで永続化できる

    最終的には ~/.ga4-credentials.json に認証情報を保存して、毎回 creds.refresh(Request()) で自動更新する運用に落ち着いた。




    Copyright 2026
    サイトマップ