GA4 API×GASで実現する高度なレポート自動化|LP×チャネル分析の完全スクリプト公開

GA4のレポートを自動化する際、APIの連携は避けて通れない道です。
この記事ではGoogle Apps Script(GAS)を使って、GA4から数値を取得し、月次でスプレッドシートに自動出力するスクリプト実装を全文解説します。

たとえば「オーガニックチャネルのみ」「/movie/というパスを含むページのみ」など、実用的な条件でフィルタしたレポートを出力したい方に向けた内容です。

1. このスクリプトでできること

  • GA4 APIとGASを使って、前月分の数値を取得
  • チャネルグループが「Organic Search」のセッションのみを抽出
  • ランディングページのパスに「/movie/」を含むもののみを抽出
  • Googleスプレッドシートにヘッダー付きで出力
  • 該当する名前のシートがないときは、シートを新規作成
  1. なお、セッション数やユーザー数での絞り込みをしたい場合は、metricFilter を使えば可能です(今回は非実装)
  2. フィルターのラベル(チャネルグループ名など)は「GA4のUIで表示されている名称」と完全一致する必要があります(大文字・スペース含む)。
    例えば「Organic」と「Organic Search」は別物として扱われるためご注意を。

2. 実行環境と注意点

このスクリプトは、Google Apps Scriptの管理画面(https://script.google.com) から実行することができます。

使用前に以下の準備を行ってください:

  1. Google Cloud コンソールでGA4 APIを有効化する
    • プロジェクトを作成し、「APIとサービス」>「ライブラリ」から Google Analytics Data API を有効にします。
  2. サービスアカウントを作成し、JSONファイルを取得
    • Google Cloud コンソールの「認証情報」画面に入り「サービスアカウントを管理」リンクをクリック。さらに画面上の「+サービスアカウントを作成」をクリックしてサービスアカウントを作成します。
    • 次に画面左ナビから「サービスアカウント」に入り、画面上の「鍵」のリンクをクリック。
      画面下にある「キーを追加」のプルダウンから「新しい鍵を作成」を選択して、キーのタイプは「Json」を選択してください。
    • すると自動的にJsonファイルがダウンロードされるので必ず保管しておいてください。
      (※スクリプト設定時に使用します)
  3. GA4の管理画面でプロパティIDを用意する
    • 管理画面の「プロパティの詳細」画面右上に書かれている数字のみのIDです。
      「G-xxxxxxxxx」で始まる測定IDではないので、ご注意ください。
  4. Googleスプレッドシートを用意する
    • 出力先となるスプレッドシートを作成し、ID(下記URLの【ここがID】の部分)とデータを出力させたいシート名をメモしておきます。
      ※例:https://docs.google.com/spreadsheets/d/【ここがID】/edit
  5. GASエディタにスクリプトを貼り付け、画面左ナビにある[サービス +]の「+」ボタンから「Google Analytics Data API(v1beta)」を追加します。
    ※これを行わないと「AnalyticsData is not defined」というエラーになります。

3. コード全文とロジック

以下にGASスクリプトのサンプルと、スクリプト使用上の注意点を書いています。
期間・フィルタ条件などは皆さま各自で書き換えてご使用ください。

GASスクリプト使用上の注意点

設定時の注意

const propertyId = 'YOUR_GA4_PROPERTY_ID'; // ← 数字のみ(例: 265085688)
const sheetId = 'YOUR_SPREADSHEET_ID'; // ← スプレッドシートID

上記の部分に、先ほど準備した、GA4のプロパティIDと、スプレッドシートのIDを入れてください。


  const serviceAccount = {
    "type": "service_account",
    "project_id": "your-project-id",
    "private_key_id": "xxxxxxxxxxxxxxxxxxxx",
    "private_key": "-----BEGIN PRIVATE KEY-----\\nYOUR_KEY\\n-----END PRIVATE KEY-----\\n",
    "client_email": "your-service-account@your-project.iam.gserviceaccount.com",
    "client_id": "123456789012345678901",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/your-service-account%40your-project.iam.gserviceaccount.com"
  };

上記の各行に、先ほど取得したJsonファイルの内容を入れていってください。

実行時の注意

実行するときは、必ず「runGa4ReportWithServiceAccount」の方を実行してください。

GASスクリプト全文

function runGa4ReportWithServiceAccount() {
  const propertyId = 'YOUR_GA4_PROPERTY_ID'; // ← 数字のみ(例: 265085688)
  const sheetId = 'YOUR_SPREADSHEET_ID';     // ← スプレッドシートID
  const sheetName = 'GA4データ出力';          // ← 任意のシート名(存在しなければ自動作成)

  const serviceAccount = {
    "type": "service_account",
    "project_id": "your-project-id",
    "private_key_id": "xxxxxxxxxxxxxxxxxxxx",
    "private_key": "-----BEGIN PRIVATE KEY-----\\nYOUR_KEY\\n-----END PRIVATE KEY-----\\n",
    "client_email": "your-service-account@your-project.iam.gserviceaccount.com",
    "client_id": "123456789012345678901",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/your-service-account%40your-project.iam.gserviceaccount.com"
  };

  const now = new Date();
  const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  const endOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0);
  const startDate = Utilities.formatDate(lastMonth, Session.getScriptTimeZone(), 'yyyy-MM-dd');
  const endDate = Utilities.formatDate(endOfLastMonth, Session.getScriptTimeZone(), 'yyyy-MM-dd');

  const jwt = createJwt(
    { alg: 'RS256', typ: 'JWT' },
    {
      iss: serviceAccount.client_email,
      scope: 'https://www.googleapis.com/auth/analytics.readonly',
      aud: serviceAccount.token_uri,
      exp: Math.floor(Date.now() / 1000) + 3600,
      iat: Math.floor(Date.now() / 1000)
    },
    serviceAccount.private_key
  );

  const tokenResponse = UrlFetchApp.fetch(serviceAccount.token_uri, {
    method: 'post',
    contentType: 'application/x-www-form-urlencoded',
    payload: {
      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      assertion: jwt
    }
  });

  const accessToken = JSON.parse(tokenResponse.getContentText()).access_token;

  const url = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}:runReport`;

  const payload = {
    dateRanges: [{ startDate, endDate }],
    dimensions: [
      { name: 'landingPage' },
      { name: 'sessionDefaultChannelGroup' }
    ],
    metrics: [
      { name: 'sessions' },
      { name: 'engagementRate' }
    ],
    dimensionFilter: {
      andGroup: {
        expressions: [
          {
            filter: {
              fieldName: 'sessionDefaultChannelGroup',
              stringFilter: {
                value: 'Organic Search',
                matchType: 'EXACT'
              }
            }
          },
          {
            filter: {
              fieldName: 'landingPage',
              stringFilter: {
                value: '/movie/',
                matchType: 'CONTAINS'
              }
            }
          }
        ]
      }
    }
  };

  const response = UrlFetchApp.fetch(url, {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + accessToken
    },
    payload: JSON.stringify(payload)
  });

  const json = JSON.parse(response.getContentText());

  const spreadsheet = SpreadsheetApp.openById(sheetId);
  let sheet = spreadsheet.getSheetByName(sheetName);
  if (!sheet) {
    sheet = spreadsheet.insertSheet(sheetName);
  } else {
    sheet.clearContents();
  }

  const headers = json.dimensionHeaders.map(h => h.name)
    .concat(json.metricHeaders.map(h => h.name));
  sheet.appendRow(headers);

  if (json.rows && json.rows.length > 0) {
    json.rows.forEach(row => {
      const dims = row.dimensionValues.map(d => d.value);
      const metrics = row.metricValues.map((m, i) => {
        return i === 1  // engagementRate
          ? (parseFloat(m.value) * 100).toFixed(2) + '%'
          : m.value;
      });
      sheet.appendRow(dims.concat(metrics));
    });
  } else {
    sheet.appendRow(['該当データなし']);
  }

  Logger.log('GA4データ出力完了');
}

function createJwt(header, claimSet, privateKey) {
  const encode = (obj) =>
    Utilities.base64EncodeWebSafe(JSON.stringify(obj)).replace(/=+$/, '');
  const encodedHeader = encode(header);
  const encodedClaim = encode(claimSet);
  const signatureInput = `${encodedHeader}.${encodedClaim}`;
  const signature = Utilities.base64EncodeWebSafe(
    Utilities.computeRsaSha256Signature(signatureInput, privateKey)
  ).replace(/=+$/, '');
  return `${signatureInput}.${signature}`;
}

GASとPythonどちらを使うべき?

GASはGoogleスプレッドシートとの親和性が高く、ノーコード寄りの環境でも扱いやすいのが特徴です。

ただし、より柔軟な条件設定やログの記録、条件別での分岐出力などを行いたい場合は、Pythonの方が優れています。

👉 Python版はこちら(Google Colabでの使用がおすすめです)

まとめ

GA4からオーガニック流入かつ特定パスに限定したセッションデータを、前月分のみ自動で抽出し、Googleスプレッドシートに転記するGASスクリプトをご紹介しました。

「レポート作成の手間を減らしたい」「定型条件で毎月データを取り出したい」──そんな方はぜひご活用ください。