完全無料で構築するSearch Console × GA4日次データ自動連携・仮説検証環境(GAS・スプレッドシート連携)

Webサイトの検索順位やアクセスを伸ばすためには、日々のデータをもとに「どの記事が伸びているか」「どの記事に改善余地があるか」を把握し、仮説を立てて施策を検証するPDCAサイクルが不可欠です。しかし、高額なSEOツールや外部サーバーを契約するのはハードルが高いと感じる方も多いのではないでしょうか。本記事では、外部の有料ツールやサーバーを一切使わず、Google Apps Script(GAS)とGoogleスプレッドシートのみを活用して、Search Console(GSC)とGoogleアナリティクス4(GA4)の日次データを完全無料で自動同期・分析・仮説検証する環境構築手順を詳しく解説します。

完全無料で実現する日次分析・仮説検証の全体像

外部サーバーやクラウド有料機能を使わず、Googleの無料標準サービスのみを組み合わせて自動化を実現するアーキテクチャです。

完全無料アーキテクチャの構成要素

  • データ収集エンジン:Google Apps Script(GAS)
    Googleが提供するサーバーレス実行環境です。完全無料で稼働し、毎朝指定した時刻に自動でAPIを実行します。
  • データソース:Search Console API & Google Analytics Data API
    どちらもGoogle公式のAPIであり、日次の集計データ取得であれば無料枠内で余裕をもって運用可能です。
  • データ蓄積・管理:Googleスプレッドシート
    日次のKPI推移、施策ログ、仮説検証のBefore/After判定を1つのシートで一元管理します。
  • 日次分析・仮説検証:定期チェックとAI活用
    蓄積された日次データを毎朝確認し、急変動の検知やタイトル修正などの改善仮説を立案・記録します。

統合管理シートのデータ構造

本仕組みでは、スプレッドシートの1行で「検索流入(GSC)」と「サイト内行動(GA4)」を横断して把握できるように設計します。

日次KPI推移シートの管理項目

  • 日付:対象の日次データの日付(確定値となる3日前を推奨)
  • [GSC] 表示回数:Google検索結果にサイトが表示された総回数
  • [GSC] クリック数:検索結果からクリックされた総回数
  • [GSC] CTR (%):検索結果におけるクリック率(クリック数 ÷ 表示回数)
  • [GSC] 平均掲載順位:検索結果におけるサイト全体の平均順位
  • [GA4] 総セッション:サイト全体の総セッション数
  • [GA4] Organic検索セッション:検索エンジンからの自然流入セッション数
  • [GA4] アクティブユーザー:サイトを訪問したユニークユーザー数
  • [GA4] エンゲージメント率 (%):10秒以上滞在または特定アクションを行ったセッションの割合
  • [GA4] 平均滞在時間 (秒):ユーザー1人あたりの平均エンゲージメント時間
  • 施策・特記事項メモ:リライト実施、新規記事公開、アルゴリズム変動などの記録

GASによる自動連携の環境構築手順

スプレッドシートを作成し、GASスクリプトを設定する具体的な手順です。所要時間は約5分で完了します。

管理用スプレッドシートの作成とApps Scriptの起動

  1. Googleドライブで新しいGoogleスプレッドシートを作成します(シート名例:「サーチコンソール日次分析・仮説検証管理シート」)。
  2. 上部メニューの「拡張機能」>「Apps Script」をクリックしてエディタを開きます。

APIサービスを2つ追加する設定

Apps ScriptからGoogleの各サービスを直接呼び出せるように、標準の「拡張サービス」を追加します。

  1. Apps Scriptエディタの左側メニューにある「サービス(+マーク)」をクリックします。
  2. 一覧から「Google Search Console API」を選択し、識別子を SearchConsole として「追加」をクリックします。
  3. 再度「サービス(+マーク)」をクリックし、一覧から「Google Analytics Data API」を選択し、識別子を AnalyticsData として「追加」をクリックします。

日次自動連携スクリプトの実装

エディタ内の コード.gs に以下のコードを貼り付けます。上部の CONFIG に対象サイトのURLとGA4のプロパティIDを設定してください。

/*
 * Google Search Console & GA4 日次データ自動連携スクリプト(完全無料)
 */

const CONFIG = {
  GSC_SITE_URL: 'https://eguweb.jp/', // Search ConsoleプロパティURL (ドメインプロパティの場合は 'sc-domain:eguweb.jp')
  GA4_PROPERTY_ID: '123456789',       // ご自身のGA4プロパティID(数字のみ)
  SHEET_NAME: '日次KPI推移',           // 書き込み先シート名
  DAYS_AGO: 3                         // データ確定ラグ(2〜3日前が確定値)
};

function fetchDailyGSCandGA4Data() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName(CONFIG.SHEET_NAME);
  
  // シートが存在しない場合はヘッダー付きで新規作成
  if (!sheet) {
    sheet = ss.insertSheet(CONFIG.SHEET_NAME);
    sheet.appendRow([
      '日付',
      '[GSC] 表示回数',
      '[GSC] クリック数',
      '[GSC] CTR (%)',
      '[GSC] 平均掲載順位',
      '[GA4] 総セッション',
      '[GA4] Organic検索セッション',
      '[GA4] アクティブユーザー',
      '[GA4] エンゲージメント率 (%)',
      '[GA4] 平均滞在時間 (秒)',
      '施策・特記事項メモ'
    ]);
    sheet.getRange(1, 1, 1, 11).setBackground('#0284c7').setFontColor('#ffffff').setFontWeight('bold');
    sheet.setFrozenRows(1);
  }

  // 対象日付(3日前)の算出
  const targetDateObj = new Date();
  targetDateObj.setDate(targetDateObj.getDate() - CONFIG.DAYS_AGO);
  const targetDateStr = Utilities.formatDate(targetDateObj, Session.getScriptTimeZone(), 'yyyy-MM-dd');

  Logger.log('取得対象日: ' + targetDateStr);

  // 1. Google Search Console APIからデータ取得
  let gscImpressions = 0;
  let gscClicks = 0;
  let gscCtr = 0;
  let gscPosition = 0;

  try {
    const gscRequest = {
      startDate: targetDateStr,
      endDate: targetDateStr,
      dimensions: []
    };
    const gscResponse = SearchConsole.Searchanalytics.query(gscRequest, CONFIG.GSC_SITE_URL);
    if (gscResponse.rows && gscResponse.rows.length > 0) {
      const row = gscResponse.rows[0];
      gscImpressions = row.impressions || 0;
      gscClicks = row.clicks || 0;
      gscCtr = row.ctr ? Number((row.ctr * 100).toFixed(2)) : 0;
      gscPosition = row.position ? Number(row.position.toFixed(1)) : 0;
    }
  } catch (e) {
    Logger.log('GSC取得エラー: ' + e.message);
  }

  // 2. Google Analytics 4 Data APIからデータ取得
  let gaSessions = 0;
  let gaOrganicSessions = 0;
  let gaUsers = 0;
  let gaEngagementRate = 0;
  let gaAvgDuration = 0;

  if (CONFIG.GA4_PROPERTY_ID && CONFIG.GA4_PROPERTY_ID !== 'YOUR_GA4_PROPERTY_ID') {
    try {
      // サイト全体指標
      const gaRequest = AnalyticsData.newRunReportRequest();
      gaRequest.dateRanges = [{ startDate: targetDateStr, endDate: targetDateStr }];
      gaRequest.metrics = [
        { name: 'sessions' },
        { name: 'activeUsers' },
        { name: 'engagementRate' },
        { name: 'userEngagementDuration' }
      ];

      const gaResponse = AnalyticsData.Properties.runReport(gaRequest, 'properties/' + CONFIG.GA4_PROPERTY_ID);
      if (gaResponse.rows && gaResponse.rows.length > 0) {
        const m = gaResponse.rows[0].metricValues;
        gaSessions = parseInt(m[0].value || '0', 10);
        gaUsers = parseInt(m[1].value || '0', 10);
        const engRateRaw = parseFloat(m[2].value || '0');
        gaEngagementRate = Number((engRateRaw * 100).toFixed(2));
        const totalDuration = parseFloat(m[3].value || '0');
        gaAvgDuration = gaUsers > 0 ? Number((totalDuration / gaUsers).toFixed(1)) : 0;
      }

      // Organic Search流入のみ抽出
      const gaOrganicRequest = AnalyticsData.newRunReportRequest();
      gaOrganicRequest.dateRanges = [{ startDate: targetDateStr, endDate: targetDateStr }];
      gaOrganicRequest.dimensions = [{ name: 'sessionDefaultChannelGroup' }];
      gaOrganicRequest.metrics = [{ name: 'sessions' }];
      gaOrganicRequest.dimensionFilter = {
        filter: {
          fieldName: 'sessionDefaultChannelGroup',
          stringFilter: { value: 'Organic Search', matchType: 'EXACT' }
        }
      };

      const gaOrganicResponse = AnalyticsData.Properties.runReport(gaOrganicRequest, 'properties/' + CONFIG.GA4_PROPERTY_ID);
      if (gaOrganicResponse.rows && gaOrganicResponse.rows.length > 0) {
        gaOrganicSessions = parseInt(gaOrganicResponse.rows[0].metricValues[0].value || '0', 10);
      }

    } catch (e) {
      Logger.log('GA4取得エラー: ' + e.message);
    }
  }

  // 重複確認と更新/追記
  const data = sheet.getDataRange().getValues();
  let rowToUpdate = -1;
  for (let i = 1; i < data.length; i++) {
    const existingDate = data[i][0];
    const formattedExisting = existingDate instanceof Date 
      ? Utilities.formatDate(existingDate, Session.getScriptTimeZone(), 'yyyy-MM-dd')
      : String(existingDate).trim();
    if (formattedExisting === targetDateStr) {
      rowToUpdate = i + 1;
      break;
    }
  }

  const rowData = [
    targetDateStr,
    gscImpressions,
    gscClicks,
    gscCtr,
    gscPosition,
    gaSessions,
    gaOrganicSessions,
    gaUsers,
    gaEngagementRate,
    gaAvgDuration,
    ''
  ];

  if (rowToUpdate > 0) {
    sheet.getRange(rowToUpdate, 1, 1, rowData.length).setValues([rowData]);
    Logger.log('既存行を更新しました: ' + rowToUpdate);
  } else {
    sheet.appendRow(rowData);
    Logger.log('新規追記完了: ' + targetDateStr);
  }
}

初回実行とアクセスの許可

  1. 上部ツールバーの関数名で fetchDailyGSCandGA4Data を選択し、「実行」をクリックします。
  2. 初回実行時は「承認が必要です」というダイアログが表示されるため、「権限を確認」をクリックして自身のアカウントを選択し、アクセスを許可します。
  3. 実行完了後、スプレッドシートを開いて「日次KPI推移」シートに3日前のデータが正しく反映されていることを確認します。

毎朝の自動実行タイマートリガーの設定

  1. Apps Scriptエディタの左側メニューにある「トリガー(時計マーク)」をクリックします。
  2. 右下の「+ トリガーを追加」をクリックし、以下のように設定します。
    • 実行する関数:fetchDailyGSCandGA4Data
    • イベントのソース:時間主導型
    • 時間ベースのトリガーのタイプ:日ベースのタイマー
    • 時刻を選択:午前6時〜7時
  3. 「保存」をクリックすれば、毎朝自動で最新データがスプレッドシートへ追記されます。

日次分析と仮説検証の運用サイクル

データが自動蓄積される環境ができたら、毎朝のルーティンとして以下の4ステップで仮説検証PDCAを回します。

仮説検証PDCAの4ステップ

  1. 日次KPIの定点観測
    前日比(DoD)や前週同曜日比(WoW)で、検索クリック数やOrganicセッションの増減傾向をチェックします。
  2. 変動・改善機会の検知
    ・急落/急上昇:掲載順位や表示回数が大きく動いた記事を特定。
    ・高表示・低CTR:検索結果で多く見られているのにクリックされていない記事(タイトル改善の最優先対象)。
    ・11位〜20位のポテンシャルクエリ:2ページ目に位置し、少しのリライトで1ページ目(10位以内)へ急伸可能なクエリ。
  3. 改善仮説の立案・実行
    「どの課題に対して」「何を変更することで」「どの指標がどう変わるか」を仮説ログに記録し、リライトを実行します(例:「タイトル冒頭に【完全無料】を追記し、CTRを3.2%から5.0%へ引き上げる」)。
  4. 効果検証と振り返り
    施策反映後(3日後・7日後・14日後)の数値を追跡し、仮説の合否判定と次のアクションを決定します。

完全無料運用における重要注意点

本手法を長期間安定して運用するために、以下の注意点と仕様を把握しておきましょう。

運用のポイントと制約

  • データの確定タイムラグ(2〜3日遅れ)
    Search ConsoleおよびGA4の集計データは、リアルタイムではなく2〜3日かけて確定します。当日の日次バッチでは「3日前」のデータを対象にすることで、ブレのない確定数値を記録できます。
  • GA4プロパティIDの確認方法
    GA4のプロパティIDは、Googleアナリティクス管理画面 >「プロパティ設定」>「プロパティの詳細」に記載されている9〜10桁の「数字のみ」を入力してください(測定ID「G-XXXXXXX」ではありません)。
  • API無料利用枠の範囲
    Google Apps Scriptおよび各APIサービスは完全無料で利用できます。GASの標準実行時間制限(1回あたり最大6分)がありますが、日次の集計データ取得処理は数秒で終了するため問題ありません。
  • プロパティURLの指定形式
    Search Consoleで「URLプレフィックス」で登録している場合は https://example.com/、「ドメインプロパティ」で登録している場合は sc-domain:example.com の形式で記述してください。

まとめ

Google Apps Scriptとスプレッドシートを組み合わせることで、高価な外部ツールやサーバー構築費をかけることなく、Search ConsoleとGA4を統合した強力なSEO分析環境を完全無料で構築できます。

毎朝の自動記録によってサイトの微細な変化を逃さず捉え、データに基づいた確実な改善PDCAを回していきましょう。