JMDC TECH BLOG

JMDCのエンジニアブログです

GA4データの自動取得をGASでやってみた

こんにちは!株式会社JMDCの黄です。

プロダクト開発部で受診勧奨サービスのプロダクト開発とPep Upのバックエンドエンジニアをしています。

GoogleスプレッドシートからGA4のデータを取得するためのカスタムGASスクリプトのサンプルを作成してみました。 この記事では、そのスクリプトのポイントを解説します。

背景

私がいるチームでは、運営中のWebサイトの一部をGoogle Analyticsを使って分析しています。昨年からGoogle AnalyticsをユニバーサルアナリティクスからGoogleアナリティクス4(GA4)に移行しました。

これまで、ユニバーサルアナリティクスのデータをGoogleスプレッドシートに同期するために、Google公式のツールを利用してきましたが、GA4移行に伴い、Google公式の「GA4 Reports Builder for Google Analytics™」という新しいツールに切り替えました。しかし、このツールは担当者から見て安定性に不安があり、2024年8月時点では評価が★1.7という状況です。

そこで、データを安定して取得できるようにするために、GASスクリプトでGA4データの自動取得ツールを使うようにしていました。 今回は、自動取得ツールの機能を一般化してどなたでも使えるようにしたサンプルスクリプトを作成して解説します。

ざっくり機能紹介

このスクリプトは、GA4のデータをGoogleスプレッドシートに自動的に取得し、整理するためのツールです。

以下の主な機能を提供しています。

スプレッドシートのメニューバーに関連メニューを追加

メニューバーに「GA4取得」のメニューを追加して、「ディメンション・メトリクス一覧の取得」と「データを取得」の両機能を起動できるようにします。

ディメンション・メトリクス一覧の取得

GA4のプロパティIDを指定すると、そのプロパティで利用可能なディメンションとメトリクスの一覧がスプレッドシートに出力されます。

データを取得

スプレッドシートの設定シートに記載された設定に基づいて、GA4からデータを取得し、指定されたシートに出力します。

データ取得フローの概要

以下の図は、このスクリプトがどのように動作するかを示したフローです。

1.ディメンション・メトリクス一覧の取得

「GA4取得」メニューから「ディメンション・メトリクス一覧を取得」をクリックし、プロパティIDを入力します。 スプレッドシートにディメンションとメトリクスの一覧が出力されます。

2.Configurationシートに項目を設定

出力されたディメンション・メトリクス一覧を参照し、必要な項目の「API Name」を Configuration シートに記入します。 Configuration シートには、出力したいレポートの設定を行います。B列以降に異なるレポートを設定することで、複数のレポートを一度に取得できます。

3.Configurationシートを基にしたデータ取得

「GA4取得」メニューから「データを取得」をクリックすると、設定に基づいてGA4のデータが取得され、指定したシートに出力されます。

使い方

実際に今回作ったサンプルスクリプトを動かして、動作を確認します。

以下手順で使えるようになります。

1. サンプルシートのコピー

以下のサンプルシートのコピーを作成します。

>>サンプルシート<<

このシートは、Google Analytics 4からデータを取得するためのフォーマットが設定されています。

2. Google Apps Script の設定

スプレッドシートにGoogle Apps Scriptを追加します。

以下の手順で追加

a.スプレッドシートのメニューから 拡張機能 > Apps Script を選択。

b.新しいスクリプトエディタが開きますので、既存のコードをすべて削除し、このGISTにあるコードをコピーして貼り付けます。

c.スクリプトを保存します。

3. Google Analytics Data API の有効化

GASスクリプトで、Google Analytics Data APIを使用しますので、APIを有効化します。

a.スクリプトエディタで、左側の + ボタンをクリックして「サービスを追加」を選択します。

b.Google Analytics Data API を見つけて、ID:AnalyticsData と指定して追加します。

※IDが間違っていると、スクリプトがAPIを正しく参照できないので注意

4.ディメンション・メトリクス一覧を取得

スプレッドシートに戻ります。 スプレッドシートのメニューにある「GA4取得」→「ディメンション・メトリクス一覧を取得」をクリックします。(必要に応じて権限付与します)

GA4のプロパティIDを求められるので、プロパティIDを入力して「OK」をクリックする

別シートにディメンションとメトリクス一覧が出力されます

5. Configuration シートに設定を記入

コピーしたサンプルシートの Configuration シートには、レポートの設定は、それぞれの項目名の内容を入力します。

Report Nameは出力するシート名です。

DimensoinsMetricsの指定に関しては、1で出力したディメンションとメトリクス一覧情報を参照してほしいパラメーターの「API Name」列をカンマ区切りで入力することで取得できます。

※指定方法は基本的に「GA4 Reports Builder for Google Analytics™」と同じです。

B列だけでなく、C列D列以降に異なるレポートの設定を記入することで、複数のレポートを一度に出力できます。

6. データの取得

スプレッドシートのメニューにある「GA4取得」→「データを取得」をクリック。

これで、設定に基づいてGA4のデータが取得され、それぞれのレポート名に基づいたシートに出力されます。

この設定とスクリプトを活用して、GA4のデータを出力できるようになります。

GASを定期実行(トリガー)させるようにすれば、定期的に実行することも可能なので、ぜひお試しください。

解説

サンプルコードGIST

サンプルシート

設計の考え方

安定して動かせる「GA4 Reports Builder for Google Analytics™」の代替品をミニマムの要件で作ることを目指しました。

GooglaAnalyticsをある程度使っている人が使う想定なので、ディメンション・メトリクスや日付・フィルターの指定はちゃんとやろうとすると非常に複雑になるので、実現しやすさを最優先しました。

ミニマムな機能

要件を満たすための必要最低限な機能は以下3つとしました

メトリクスとディメンションの取得

GA4のプロパティIDを指定して、該当プロパティのディメンションとメトリクスを取得します。 これで該当のプロパティで指定できるものがわかるようになります。 カスタムパラメーターがある場合は、ドキュメントを参照しても指定方法がわからないので、この機能は必須です。

レポートの抽出設定通りにGAデータを取得

Configuration シートに記載されたレポートの出力設定を取得します。 ここで、ほしいディメンション・メトリクスや期間などを指定できます。 チーム内で必要なデータをすべて効率的に同期できるようにしたいので、複数のレポートを一度に指定できるようにします。

スプレッドシートへの出力

取得したデータを指定されたシート名で出力します。

各機能の実現方法の解説

1. メニューの追加

Googleスプレッドシートを開くとカスタムメニューが追加するようにしています。 このメニューから、メトリクスとディメンションの取得、データの取得を選択できるようになります。

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  // カスタムメニュー
  ui.createMenu('GA4取得')
    .addItem('ディメンション・メトリクス一覧を取得', 'getMetadataPrompt')
    .addItem('データを取得', 'fetchReports')
    .addToUi();
}

2. プロパティIDの入力とメトリクス一覧の取得

プロパティIDを入力することで、そのプロパティに関連するメトリクスとディメンションの一覧を取得します。 取得したデータは、それぞれ専用のシートに出力されるようにします。 getMetadataPrompt()で、プロパティIDを入力してもらい、getMetadata()で該当プロパティのメトリクスとディメンションを取得します。

ここでは、Google Analytics Data API を使ってデータを取得しています。

また、GASでスプレッドシートのデータを編集する際、1セルずつデータを追加すると莫大な時間がかかるので、setValues()を使うようにしています。

function getMetadataPrompt() {
  const ui = SpreadsheetApp.getUi();
  const response = ui.prompt('プロパティIDを入力してください:');
  const propertyId = response.getResponseText();
  
  if (!propertyId) {
    ui.alert('プロパティIDが入力されていません。');
    return;
  }

  getMetadata(propertyId);
}

// メトリクス一覧の取得
const getMetadata = (propertyId) => {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  
  try {
    // APIへリクエストを送りレスポンスを受け取る
    const metadata = AnalyticsData.Properties.getMetadata(`properties/${propertyId}/metadata`);
    const { dimensions, metrics } = metadata;
    
    // ディメンション情報をシートに出力
    const dimensionsSheet = ss.getSheetByName(`dimensions_${propertyId}`) || ss.insertSheet(`dimensions_${propertyId}`);
    dimensionsSheet.clear();
    const dimensionValues = [['Category', 'API Name', 'UI Name', 'Description'], ...dimensions.map(dimension => [
      dimension.category, dimension.apiName, dimension.uiName, dimension.description
    ])];
    dimensionsSheet.getRange(1, 1, dimensionValues.length, dimensionValues[0].length).setValues(dimensionValues);
    
    // メトリクス情報をシートに出力
    const metricsSheet = ss.getSheetByName(`metrics_${propertyId}`) || ss.insertSheet(`metrics_${propertyId}`);
    metricsSheet.clear();
    const metricValues = [['Category', 'API Name', 'UI Name', 'Description'], ...metrics.map(metric => [
      metric.category, metric.apiName, metric.uiName, metric.description
    ])];
    metricsSheet.getRange(1, 1, metricValues.length, metricValues[0].length).setValues(metricValues);
    
  } catch (e) {
    Browser.msgBox("ERROR", e.message, Browser.Buttons.OK);
  }
}

3. レポートの取得

Configuration シートに設定された各レポート設定を順番に読み込み、設定通りにGA4からデータを取得します。

const fetchReports = () => {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const configSheet = ss.getSheetByName('Configuration');
  const lastColumn = configSheet.getLastColumn();
  const configData = configSheet.getRange(1, 2, 10, lastColumn - 1).getValues();  // B1〜最終列までのデータを取得

  configData[0].forEach((_, col) => {
    const reportName = configData[0][col];
    const propertyId = configData[1][col];
    const startDate = configData[2][col];
    const endDate = configData[3][col];
    
    const metrics = configData[4][col] ? configData[4][col].split(',').map(metric => AnalyticsData.newMetric().setName(metric.trim())) : [];
    const dimensions = configData[5][col] ? configData[5][col].split(',').map(dimension => AnalyticsData.newDimension().setName(dimension.trim())) : [];

    const limit = configData[7][col] ? parseInt(configData[7][col], 10) : 1000;

    const report = fetchData(propertyId, metrics, dimensions, startDate, endDate, limit);
    if (report) {
      const sheet = ss.getSheetByName(reportName) || ss.insertSheet(reportName);
      outputToSheet(report, sheet);
    }
  });
}

const fetchData = (propertyId, metrics, dimensions, startDate, endDate, limit) => {
  try {
    const dateRange = AnalyticsData.newDateRange();
    dateRange.startDate = startDate;
    dateRange.endDate = endDate;

    const request = AnalyticsData.newRunReportRequest();
    request.dimensions = dimensions;
    request.metrics = metrics;
    request.dateRanges = [dateRange];
    request.limit = limit;

    return AnalyticsData.Properties.runReport(request, `properties/${propertyId}`);
  } catch (e) {
    console.error('Failed with error: %s', e.message);
    return null;
  }
}

4.データをシートに出力

取得したデータは、指定されたシート名のシートに出力します。

こちらもsetValues()を使うようにしています。

const outputToSheet = (report, sheet) => {
  if (!report || !report.rows) {
    console.error('No rows returned.');
    return;
  }

  // シートの既存データをクリア
  sheet.clear();

  const headers = [...report.dimensionHeaders.map(header => header.name), ...report.metricHeaders.map(header => header.name)];
  sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
  
  const rows = report.rows.map(row => [
    ...row.dimensionValues.map(dimensionValue => dimensionValue.value),
    ...row.metricValues.map(metricValue => metricValue.value)
  ]);
  
  sheet.getRange(2, 1, rows.length, headers.length).setValues(rows);
}

終わりに

ユニバーサルアナリティクスからGA4になって、データ取得で困ってた方は私だけではないはずです。

どなたかの参考になれば嬉しいです!

JMDCでは、ヘルスケア領域の課題解決に一緒に取り組んでいただける方を積極採用中です!フロントエンド /バックエンド/ データベースエンジニア等、様々なポジションで募集をしています。詳細は下記の募集一覧からご確認ください。 hrmos.co

まずはカジュアルにJMDCメンバーと話してみたい/経験が活かせそうなポジションの話を聞いてみたい等ございましたら、下記よりエントリーいただけますと幸いです。 hrmos.co

★最新記事のお知らせはぜひ X(Twitter)、またはBlueskyをご覧ください!

twitter.com

bsky.app