[GAS] GA4データをAPI経由でスプシに反映 (フィルタ設定つき)

▼ 作成した全スクリプトは末尾にあります

表題のようなGASのスクリプトを探していたら、ちょうどヤマタケさんのブログ↓でいい感じのスクリプトを見つけまして、

GASでGA4のAPIフィルタ設定方法を解説!(文字列・数値フィルタのコード付き) | AutoWorker〜Google Apps Script(GAS)とSikuliで始める業務改善入門
Google Apps Script(GAS)には、GA4のAPIである「Google Analytics Data API」をサービス追加で簡単に利用できます。 ただ、指標やディメンションの設定は…
auto-worker.com

早速使わせて頂いているのですが(ありがとうございます!)、運用的に使いやすくなるように少しだけ改造してみました。

まず1つ目、測定期間は前月の初日〜末日になることが多いので、

  // 前月の1日と末日を取得
  var date = new Date();
  var lastMonth1st = new Date(date.getFullYear(), date.getMonth()-1, 1).toLocaleDateString("ja-JP", {year: "numeric",month: "2-digit", day: "2-digit"}).replaceAll('/', '-');
  var lastMonthEnd = new Date(date.getFullYear(), date.getMonth(), 0).toLocaleDateString("ja-JP", {year: "numeric",month: "2-digit", day: "2-digit"}).replaceAll('/', '-');

のブロックを追加して、「前月の初日」と「前月の末日」を算出し、測定期間の設定に使用。

次に、元のソース(下記)

    //GA4から取得する指標を設定する
    const metric = [AnalyticsData.newMetric(),AnalyticsData.newMetric()];
    metric[0].name = 'sessions';
    metric[1].name = 'averageSessionDuration';

のうち、
const metric = [AnalyticsData.newMetric(),AnalyticsData.newMetric()];
の行の更新が面倒だなーと思ったので、

  const metricList = ['sessions','engagementRate'];
  let metric = [];
  for(i=0; i<metricList.length; i++){
    metric[i] = AnalyticsData.newMetric();
    metric[i].name = metricList[i];
  }

という感じに改造しました。(ディメンション設定部分も同様)

最後にスプレッドシートへの出力用スクリプト↓を追加して・・・

  // スプレッドシート設定
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheetTitle = lastMonth1st + "〜" + lastMonthEnd;
  try {
    ss.insertSheet(sheetTitle);
  } catch (e) {
  }
  //出力先のスプレッドシートID
  const SPREADSHEET_ID = "******************************";
  //出力先のシート名
  const SHEET_NAME = sheetTitle;

  //スプレッドシートにレポートを出力
  const spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = spreadsheet.getSheetByName(SHEET_NAME);
  sheet.clear();

  sheet.appendRow(headers);
  sheet.getRange(2, 1, report.rows.length, headers.length).setValues(rows);

※スプレッドシートIDは下図URLの赤枠部分になります

全体では、下記のような感じになりました。

スクリプトを実行すると、シート名「YYYY-MM-DD〜YYYY-MM-DD」の新規シートを作成し、前月のレポートを出力します。
もし同名のシートが作成済みの場合は、そのまま上書きしてしまうのでご注意ください。
(同一シートの末尾にデータ追加していくスクリプトも作成可能)

なお、定期実行される場合は、毎月3日0時ぐらいに設定するのをお勧めします。データ反映に24時間以上かかっている事例を複数見ていますので、くれぐれもご注意ください。

▼今回作成したスクリプト(全体)

function runGa4Report() {
  //GA4のプロパティIDを設定 ※GA4プロパティIDをセット
  const propertyId = '*********';

  // 前月の1日と末日を取得
  var date = new Date();
  var lastMonth1st = new Date(date.getFullYear(), date.getMonth()-1, 1).toLocaleDateString("ja-JP", {year: "numeric",month: "2-digit", day: "2-digit"}).replaceAll('/', '-');
  var lastMonthEnd = new Date(date.getFullYear(), date.getMonth(), 0).toLocaleDateString("ja-JP", {year: "numeric",month: "2-digit", day: "2-digit"}).replaceAll('/', '-');

  // スプレッドシート設定
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheetTitle = lastMonth1st + "〜" + lastMonthEnd;
  try {
    ss.insertSheet(sheetTitle);
  } catch (e) {
  }
  //出力先のスプレッドシートID
  const SPREADSHEET_ID = "******************************";
  //出力先のシート名
  const SHEET_NAME = sheetTitle;

  //ディメンション設定
  const dimensionList = ['sessionDefaultChannelGroup','landingPage'];
  let dimension = [];
  for(i=0; i<dimensionList.length; i++){
    dimension[i] = AnalyticsData.newDimension();
    dimension[i].name = dimensionList[i];
  }

  //ディメンションフィルタ設定
  let dimensionfilter = AnalyticsData.newFilterExpressionList();
  dimensionfilter.andGroup = AnalyticsData.newFilterExpressionList();
  dimensionfilter.andGroup.expressions = [];

  //ディメンションフィルタ1
  let dimensionFilter1Expression = AnalyticsData.newFilterExpression();
  dimensionFilter1Expression.filter = AnalyticsData.newFilter();
  dimensionFilter1Expression.filter.fieldName = 'sessionDefaultChannelGroup';
  dimensionFilter1Expression.filter.stringFilter = AnalyticsData.newStringFilter();
  dimensionFilter1Expression.filter.stringFilter.value = 'organic';
  dimensionFilter1Expression.filter.stringFilter.matchType = 'CONTAINS';
  dimensionfilter.andGroup.expressions.push(dimensionFilter1Expression);

  //ディメンションフィルタ2
  let dimensionFilter2Expression = AnalyticsData.newFilterExpression();
  dimensionFilter2Expression.filter = AnalyticsData.newFilter();
  dimensionFilter2Expression.filter.fieldName = 'landingPage';
  dimensionFilter2Expression.filter.stringFilter = AnalyticsData.newStringFilter();
  dimensionFilter2Expression.filter.stringFilter.value = '/movie/';
  dimensionFilter2Expression.filter.stringFilter.matchType = 'CONTAINS';
  dimensionfilter.andGroup.expressions.push(dimensionFilter2Expression);

  //メトリック(指標)設定
  const metricList = ['sessions','engagementRate'];
  let metric = [];
  for(i=0; i<metricList.length; i++){
    metric[i] = AnalyticsData.newMetric();
    metric[i].name = metricList[i];
  }

  //メトリックフィルタ設定
  let metricfilter = AnalyticsData.newFilterExpressionList();
  metricfilter.andGroup = AnalyticsData.newFilterExpressionList();
  metricfilter.andGroup.expressions = [];
  
  //メトリックフィルタ1
  let metricfilter1Expression = AnalyticsData.newFilterExpression();
  metricfilter1Expression.filter = AnalyticsData.newFilter();
  metricfilter1Expression.filter.fieldName = 'sessions';
  metricfilter1Expression.filter.numericFilter = AnalyticsData.newNumericFilter();
  metricfilter1Expression.filter.numericFilter.operation = 'GREATER_THAN';
  let numericValue = AnalyticsData.newNumericValue();
  numericValue.doubleValue = 10;
  metricfilter1Expression.filter.numericFilter.value = numericValue;
  metricfilter.andGroup.expressions.push(metricfilter1Expression);

  //取得するデータ期間を設定
  const dateRange = AnalyticsData.newDateRange();
  dateRange.startDate = lastMonth1st;
  dateRange.endDate = lastMonthEnd;

  //これまで設定した各種設定をリクエストにセット
  const request = AnalyticsData.newRunReportRequest();
  request.dimensions = dimension;
  request.metrics = metric;
  request.dateRanges = dateRange;
  request.dimensionFilter = dimensionfilter;
  request.metricFilter = metricfilter;

  //GA4のAPIにリクエスト
  const report = AnalyticsData.Properties.runReport(request,'properties/' + propertyId);
  if (!report.rows) {
    Logger.log('取得できるデータがありませんでした。');
    return;
  }    

  //ディメンションのヘッダー情報を取得
  const dimensionHeaders = report.dimensionHeaders.map(
      (dimensionHeader) => {
        return dimensionHeader.name;
      });
  //指標のヘッダー情報を取得
  const metricHeaders = report.metricHeaders.map(
      (metricHeader) => {
        return metricHeader.name;
      });
  const headers = [...dimensionHeaders, ...metricHeaders];

  const rows = report.rows.map((row) => {
    const dimensionValues = row.dimensionValues.map(
        (dimensionValue) => { 
          return dimensionValue.value;
        });
    const metricValues = row.metricValues.map(
        (metricValues) => {
          return metricValues.value;
        });
    return [...dimensionValues, ...metricValues];
  });

  //スプレッドシートにレポートを出力
  const spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = spreadsheet.getSheetByName(SHEET_NAME);
  sheet.clear();

  sheet.appendRow(headers);
  sheet.getRange(2, 1, report.rows.length, headers.length).setValues(rows);

}

以上、ご参考になれば幸いです。

ちなみにBigQuery経由のスクリプトも作りかけましたが、SQLの処理が面倒くさそうなので、いったん保留にしました。

PythonのようにSQLコピペで動作するようになってくれればいいのになー
(無理だろうけど)

今回はじめてGASをがっつりいじりましたが、GASは確かに JavaScript そのものだなと実感しました。
良い意味でも悪い意味でもw