GAS:GoogleAppsScript / GoogleAppSheetグーグルアナリティクス(Analytics)

GoogleAnalytics(GA4)のデータをAPIで読み取って分析する自作アプリ、徐々に改善しています

この記事は約18分で読めます。

Gemini × GASで自社専用の「Googleアナリティクス解析アプリ」Gemini × GASで自社専用の「Googleアナリティクス解析アプリ」。対象のWEBサイトのアクセス解析を約1分で作成してくれる自作のWEBアプリです。便利なので活用していますが、使い込んでくると少しずつ改善したくなっていきますね。
今回はこのWEBアプリに折れ線グラフを追加してみました。

GASとGeminiで作成したWEBアプリ

GoogleAnalytics(GA4)のWEBアプリに折れ線グラフを追加

このWEBアプリについては先月のブログで紹介しています。

【非エンジニアでも開発可能】Gemini × GASで自社専用の「Googleアナリティクス解析アプリ」を作ってみた
今回は、社内の業務効率化のために自作した「Googleアナリティクス解析Webアプリ」についてご紹介します。「アプリ開発」というと、専門的なプログラミング知識が必要なイメージがあるかもしれません。実際、私はエンジニアではありませんし、コードも自分では書けません。しかし、生成AI(Gemini)を活用することで、なんと自分専用の解析ツールを完成させることができました。いわゆるバイブコーディングという...
Geminiと会話するだけで「自分専用GA4解析アプリ」を作って運用がとっても便利です【AI開発】
Googleアナリティクス4(GA4)を使っていると、「もっと手軽に、自分のサイトに合った分析が見たい」と思うことはありませんか? 高機能な有料ツールを入れるほどではないけれど、デフォルトの管理画面は少し見づらい…。そこで今月1日に、Google Apps Script (GAS) と Gemini API を組み合わせて、「自分専用のGA4解析WEBアプリ」 を自作してみました。「自作」と言って...

このときは、折れ線グラフはありませんでした。当初はそれでもいいかと思っていましたが、やはり折れ線グラフがあると臨場感が違います。そこで、折れ線グラフを追加で表示できるようにアプリを修正しました。

GA4を自作のアプリで読み取ってグラフ表示

無事に折れ線グラフが表示できるようになりました。

実際に修正した手順を紹介します

まず、これまで利用していたアプリで出力した画面のスクショを使い、Geminiに自分が実現したい仕様を実装可能かどうかを確認しました。

あらたにGeminiに以下のような質問(プロンプト)を入れました

どもども遠田
どもども遠田

このような仕様でアプリ修正ができるかどうかを確認

するとGeminiからは以下のような回答がありました。

AIの回答
AIの回答

素晴らしいツールですね!Google Apps Script (GAS) とGA4 API、そしてGeminiを組み合わせた独自のレポートツール、デザインも清潔感があり、スコアリング機能(「85点 A」など)も直感的で非常に分かりやすいです。

ご質問の「折れ線グラフの表示」は可能です。 また、現在のUIをベースに、さらに実用的でリッチなレポートにするためのブラッシュアップ案をいくつか提案します。

修正は可能なようです。
そこでGeminiからの提案を確認しました。

折れ線グラフを実装する方法(技術的なアプローチ)

現在のGoogle Apps Script (GAS) + HTML構成であれば、「Chart.js」 というJavaScriptライブラリを使うのが最も標準的で簡単です。

実装のステップ:

  1. GA4 APIリクエストの変更: 現在は「期間合計」だけを取得しているようですが、折れ線グラフには「日別」のデータが必要です。APIリクエストの dimensionsdate を追加してデータを取得します。

    JSON

    // APIリクエストのイメージ
    {
      "dateRanges": [{ "startDate": "30daysAgo", "endDate": "yesterday" }],
      "dimensions": [{ "name": "date" }], // ←ここが重要
      "metrics": [{ "name": "activeUsers" }]
    }
    
  2. HTML側での描画: HTMLファイル側で Chart.js を読み込み、取得した日別データを渡して描画します。

デザイン上の配置アイデア:

  • A案:カード内に「スパークライン」として表示 現在のカード(ユーザー数など)の右側にある棒グラフの代わりに、小さな折れ線グラフ(スパークライン)を表示します。推移の傾向(上昇中か下降中か)を一目で把握できます。

  • B案:メインの大きなグラフを追加 カードの下に大きな描画エリアを作り、ユーザー数とPVの日次推移を大きく表示します。「昨対比」の点線を重ねると、成長度がより明確になります。

コンテンツ・デザインのブラッシュアップ案

現状の良いデザインを活かしつつ、さらに分析価値を高めるアイデアです。

A. Geminiによる分析の深化(トレンド分析)

現在は「数値の合計」に対するコメントのようですが、折れ線グラフ用の「日別データ」もGeminiに渡すことで、以下のような分析が可能になります。

  • 「○月○日に急激なスパイクがあります。これは特定の記事がバズった可能性があります。」

  • 「週末にアクセスが落ちる傾向があるため、BtoBの検索意図が強いサイトと言えます。」 といった、時系列に基づいたインサイトを出力させることができます。

B. 流入経路(チャネル)の内訳表示

全体の数値が伸びていても、「自然検索(SEO)」が伸びたのか、「SNS」が伸びたのかで対策が異なります。

  • 提案: 「ユーザー数」カードをクリック、またはその下に「Organic Search / Direct / Social」の割合を示す円グラフや、内訳の棒グラフを追加すると、SEOの成果(キャプチャ内のコメントにある「コンテンツSEOの成果」)がより視覚的に裏付けられます。

C. コンバージョン(CV)の詳細化

CVRが0.05%と表示されていますが、サイトによってはCVの種類が複数あるはずです(資料請求、問い合わせ、購入など)。

  • 提案: 「コンバージョン 18件」の内訳を表示するか、もっとも重要なCVに絞ってフォーカスできるようにすると、ビジネスへの貢献度が見えやすくなります。

具体的なコードのイメージ(Chart.jsの例)

もし実装される場合、HTML側には以下のようなコードを追加することになります。

HTML

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<canvas id="myChart"></canvas>

<script>
  const ctx = document.getElementById('myChart');

  // GASから受け取ったデータを入れる
  new Chart(ctx, {
    type: 'line', // 折れ線グラフ
    data: {
      labels: ['1日', '2日', '3日', ...], // 日付
      datasets: [{
        label: 'ユーザー数',
        data: [120, 150, 180, ...], // 数値
        borderColor: '#36A2EB', // 線の色
        tension: 0.4 // 曲線の滑らかさ
      }]
    },
    options: {
      responsive: true,
      plugins: {
        legend: { display: false } // 凡例を消してシンプルに
      }
    }
  });
</script>

私がご協力できる次のステップ:

  • Chart.jsを組み込むための具体的なGAS側のコード修正案(日別データの取得処理など)を作成しましょうか?

  • あるいは、現在のレポート画面のHTML/CSS構造に合わせて、どこにグラフを配置するとバランスが良いか、レイアウトの修正案をコードベースで提示することも可能です。

どちらの方向で進めるのが良さそうでしょうか?

次のステップでは既存コードを読んでもらいます

どもども遠田
どもども遠田

既存コードを読み込ませる

現在、利用している「コード.gs」と「index.html」をテキストでアップロードしてGeminiに読み込ませます。そのうえで、このコードを改造してもらうようにしました。
※改造舌コードを生成できますか?というように「した」を「舌」というように誤変換してましたが、問題なく処理してくれました。(笑)

AIの回答
AIの回答

ご提示いただいたコード(code.jsindex.html)をベースに、日別の推移(ユーザー数とPV数)を表す折れ線グラフを追加する実装案を作成しました。

ご要望通り、GAS側で日別データを取得し、HTML側でChart.jsを使って描画するようにコードを改造します。

修正が必要な箇所は主に3点です。

GAS側 (code.js) の修正

runAnalysis 関数内で日別データを取得する処理を追加し、新しい関数 fetchDailySeries を作成します。

変更点:

  • fetchDailySeries 関数をファイルの末尾などに追加してください。

  • runAnalysis 関数の中に、fetchDailySeries を呼び出す行を追加します。

JavaScript

// code.js の runAnalysis 関数内 (189行目あたり) を修正

    // ... (前略)
    // ページランキング取得
    let topPages = [];
    try {
      topPages = fetchTopPages(propertyId, dates);
    } catch (e) {
      Logger.log("ランキング取得エラー: " + e.toString());
    }

    // ▼▼▼ 【追加】日別トレンドデータの取得 ▼▼▼
    let dailyTrend = { dates: [], users: [], pvs: [] };
    try {
      dailyTrend = fetchDailySeries(propertyId, dates);
    } catch (e) {
      Logger.log("日別データ取得エラー: " + e.toString());
    }
    // ▲▲▲ 【追加終わり】 ▲▲▲

    // ▼▼▼ EC・アフィリエイト判定とデータ取得 ▼▼▼
    let topProducts = [];
    // ... (中略) ...

    return {
      ga: gaData,
      topPages: topPages,
      dailyTrend: dailyTrend, // ←【追加】これを戻り値に含める
      ecData: {
        isEcSite: isEcSite,
// ... (後略)

追加する関数 (code.js の一番下に追加):

JavaScript

// =======================================================
//  9. 【追加】日別推移データの取得 (折れ線グラフ用)
// =======================================================
function fetchDailySeries(propertyId, dates) {
  const request = {
    dateRanges: [{ startDate: dates.currentStart, endDate: dates.currentEnd }],
    dimensions: [{ name: 'date' }],
    metrics: [
      { name: 'activeUsers' },
      { name: 'screenPageViews' }
    ],
    orderBys: [{ dimension: { dimensionName: 'date' } }],
    keepEmptyRows: true
  };

  try {
    const response = AnalyticsData.Properties.runReport(request, 'properties/' + propertyId);
    if (!response.rows) return { dates: [], users: [], pvs: [] };

    const labels = [];
    const users = [];
    const pvs = [];

    response.rows.forEach(row => {
      // 日付フォーマット整形 (YYYYMMDD -> MM/DD)
      const d = row.dimensionValues[0].value;
      const formattedDate = d.substring(4, 6) + '/' + d.substring(6, 8);
      
      labels.push(formattedDate);
      users.push(Number(row.metricValues[0].value));
      pvs.push(Number(row.metricValues[1].value));
    });

    return { dates: labels, users: users, pvs: pvs };
  } catch (e) {
    Logger.log("Trend fetch failed: " + e.toString());
    return { dates: [], users: [], pvs: [] };
  }
}

HTML側 (index.html) のレイアウト修正

グラフを表示するためのキャンバス(描画エリア)を追加します。メトリクス(数値カード)の下あたりが見やすいでしょう。

変更点:

  • <div class="metrics-grid" id="metrics-grid"></div> の直下にグラフ用エリアを追加します。

HTML

<div class="metrics-grid" id="metrics-grid"></div>

        <div class="chart-section-wrapper" style="background:#fff; padding:15px; border-radius:8px; border:1px solid #e0e0e0; margin-bottom:25px;">
           <h3 style="margin:0 0 15px 0; font-size:14px; color:#2c3e50; border-left:4px solid #3498db; padding-left:10px;">📈 期間推移 (ユーザー数 vs PV数)</h3>
           <div style="position: relative; height: 300px; width: 100%;">
             <canvas id="mainTrendChart"></canvas>
           </div>
        </div>
        <div id="ec-section" style="display:none; margin-bottom: 25px;">

HTML側 (index.html) のスクリプト修正

受け取ったデータを使ってグラフを描画する処理を追加します。

変更点:

  • renderReport 関数の中で、新しいグラフを描画する処理を呼び出します。

JavaScript

// index.html の scriptタグ内 renderReport関数 (127行目あたり)

        const ga = result.ga;
        const ai = result.gemini;
        const info = result.siteInfo;
        const topPages = result.topPages;
        const ec = result.ecData;
        const trend = result.dailyTrend; // ←【追加】データを取り出す

// ... (中略: メトリクス描画処理の後、160行目の手前あたり) ...
        
        }); // metricsDef.forEach の閉じカッコ

        // ▼▼▼ 【追加】メイン折れ線グラフの描画 ▼▼▼
        if (trend && trend.dates.length > 0) {
            const ctxTrend = document.getElementById('mainTrendChart').getContext('2d');
            
            // 既存のグラフがあれば破棄(再描画時のバグ防止)
            if (window.myTrendChart instanceof Chart) {
                window.myTrendChart.destroy();
            }

            window.myTrendChart = new Chart(ctxTrend, {
                type: 'line',
                data: {
                    labels: trend.dates,
                    datasets: [
                        {
                            label: 'ユーザー数',
                            data: trend.users,
                            borderColor: '#3498db', // 青
                            backgroundColor: 'rgba(52, 152, 219, 0.1)',
                            borderWidth: 2,
                            tension: 0.3, // 曲線のなめらかさ
                            yAxisID: 'y'
                        },
                        {
                            label: 'ページビュー',
                            data: trend.pvs,
                            borderColor: '#e67e22', // オレンジ
                            backgroundColor: 'rgba(230, 126, 34, 0.1)',
                            borderWidth: 2,
                            borderDash: [5, 5], // 点線にする
                            tension: 0.3,
                            yAxisID: 'y1' // 2軸目を使用
                        }
                    ]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    interaction: {
                        mode: 'index',
                        intersect: false,
                    },
                    plugins: {
                        legend: { position: 'top' },
                        tooltip: { 
                            backgroundColor: 'rgba(0,0,0,0.8)',
                            padding: 10
                        }
                    },
                    scales: {
                        x: {
                            grid: { display: false }
                        },
                        y: {
                            type: 'linear',
                            display: true,
                            position: 'left',
                            beginAtZero: true,
                            title: { display: true, text: 'ユーザー数' }
                        },
                        y1: {
                            type: 'linear',
                            display: true,
                            position: 'right',
                            grid: { drawOnChartArea: false }, // グリッド線を重ねない
                            beginAtZero: true,
                            title: { display: true, text: 'PV数' }
                        }
                    }
                }
            });
        }
        // ▲▲▲ 【追加終わり】 ▲▲▲

        document.getElementById('analysis-comment').textContent = ai.analysis_comment;

導入手順のまとめ

  1. code.js: 一番下に fetchDailySeries 関数を貼り付け、runAnalysis 内で呼び出して return オブジェクトに追加します。

  2. index.html (HTML部分): <div class="metrics-grid"> の直後に、グラフ用の <div class="chart-section-wrapper">...</div> を挿入します。

  3. index.html (JS部分): renderReport 関数内に、Chart.js で折れ線グラフ (type: 'line') を描画するコードを追加します。

これで、レポートの「数値カード」の下に、ユーザー数(左軸・青実線)とPV(右軸・オレンジ点線)の推移グラフが表示されるようになります。

ここからは微調整

実際に提供されたコードを貼って動かしてみました。グラフの表示はできましたが、少し問題がありました。「対前年のと今年のユーザー数」という表示が希望でしたが、「今年のユーザー数とPV数」になっていました。

グラフの修正

ここをさらに修正してもらいました。

このように、何度もやりとりすれば最終的に希望するような修正ができました。

このような感じで自作アプリを常にブラッシュアップできるのが、バイブコーディングのよい点です。

とくにGoogleWorkspace内だけで完結する「Gemini+GAS」は情報がGoogleの外部に漏れないのでセキュリティ的にも安心です。

GAS:GoogleAppsScript / GoogleAppSheet

GASはGoogleが提供しているスクリプトです。JAVA形式で記述する「Google Apps Script」のことを指すことが多いですが、ノーコードで記入できる「Google App Sheet」もGASといわれています。
簡易な開発案件ならGASで可能になりました。エクセルのような仕様なら、IT事業者に外注しなくても社内で開発し運用することも可能です。

ぜひ、一般ユーザーであるみなさんも、自社業務を改善する自作アプリに取り組んでもらいたいと思います。