microCMS

GA4と連携してJamstack構成のサイトでPV数ランキングを作る方法

岸本 彬

こんにちは、株式会社メンバーズ メンバーズルーツカンパニーの岸本です。

普段はフロントエンドエンジニアとして、主にmicroCMSとAstroを使用したJamstack構成の開発を行っています。

メンバーズルーツカンパニーでは、今までにmicroCMSとAstroを利用したJamstack構成での開発を複数行ってきました。
開発する中で出てくる要望として、「Google Analytics 4(以下、GA4)と連携したPV数ランキングを表示したい」というものがあります。

例えばWordPressでは、Simple GA4 Rankingなどのプラグインを使用することで比較的簡単にGA4と連携したPV数ランキングを実装することが可能です。しかし、microCMSにはGA4と連携する標準機能はありません。
そこで本記事では、Jamstack構成のサイトでGA4と連携し、PV数ランキングを実装する方法をご紹介いたします。

※本記事では、PV数ランキングを実現するうえでのmicroCMSでのデータの持ち方や、GA4およびAWSの各種サービスとの連携方法などについて主に解説します。フロントエンド側の実装についての詳細は割愛させていただきますので、あらかじめご了承ください。

PV数ランキングの実装について

PV数ランキングの定義

今回は、以下のような条件で記事のPV数ランキングを表示するケースを考えます。

  • 過去7日間のPV数が高い順に上から記事を表示
  • 毎週月曜日にランキングを更新


更新のタイミングや集計日数などは、後述する集計スクリプトでお好みの条件に調整することもできます。

PV数ランキングの設計

GA4と連携したPV数ランキングの設計は、データの保存場所や処理タイミングなど、いくつかのパターンを考えることができます。

今回はmicroCMS上にランキング用のAPIを作成し、定期的にGA4の閲覧データをmicroCMSに登録し、更新タイミングでビルドを行うという方法で実装を行います。

この実装方法は以下のようなメリットとデメリットがあります。

メリット

  • ランキングデータを保存するサーバーを自前で用意する必要がない
  • microCMS上で必要に応じてランキングを手動で変更することができる(※ただし、手動変更した値は定期更新で上書きされるため、手動変更時は定期更新の停止が必要)
  • microCMSのコンテンツAPIを利用してランキングデータを取得できる


デメリット

  • 定期更新でランキングデータを変更するため、リアルタイムでは更新されない
  • microCMSのAPIをランキング用に1つ使用する


特に、リアルタイムに結果を表示するなどの仕様には対応できないので、そうした運用が必要な場合は別の方式をご検討ください。

それでは、以降で順を追って実装方法を説明します。

1. microCMS上にランキング用のAPIを作成

microCMS上にランキングのデータを保存するため、ランキング用のAPIを作成します。
APIは以下のような構成にします。

APIの型:オブジェクト形式
スキーマ構成

  • 繰り返しフィールド: posts

カスタムフィールド(posts)

  • タイトル: テキストフィールド
  • URL: テキストフィールド
  • PV数: 数字フィールド
  • アイキャッチURL: テキストフィールド

1-1. APIの作成

1. オブジェクト形式でランキング用のAPIを作成

2. postsというIDのカスタムフィールドを作成

3. カスタムフィールドのスキーマにタイトル、URL、PV数、アイキャッチURLのフィールドを設定

4. 作成したカスタムフィールドをAPIスキーマに繰り返しフィールドとして設定

これでAPIの作成は完了です。完成したAPIは以下のような表示になります。

ランキングデータが登録されているときは以下のようになります。上から順番にPV数が多い順に並べられます。

1-2. Webhookの設定

作成したAPIが変更されるごとにビルドを行うために、Webhookの設定を行います。

Webhookの通知タイミング設定のうち、「コンテンツの公開(APIによる操作)」のチェックボックスにチェックをします。

集計スクリプトによってAPIのランキング情報が更新されるので、「APIによる操作」のチェックが必須になります。

集計スクリプトとは別に手動でのランキング変更も行いたい方は「コンテンツの公開(管理画面による操作)」をチェックしてください。

1-3. APIキーの設定

ランキング更新の際に、microCMSのコンテンツAPI(PATCH)を使用します。デフォルトで用意されているAPIキーの設定はPATCH権限が許可されていないため、許可設定を行います。

APIキーの追加が可能な場合はPATCH権限を許可するAPIキーを新たに作成します。APIキーをこれ以上追加するのが難しい場合は既存のAPIキーの設定を変更してください。

APIキー設定の個別権限設定から対象APIで先ほど作成した「ランキング」を選び、PATCHにチェックを入れます。
このAPI全体ではなく、個別のランキングAPIだけにPATCH権限を付与することで、万が一APIキーが流出し悪用された場合も、被害をランキングだけに留めておくことができます。

とはいえ、PATCH権限はmicroCMS上のコンテンツを編集することができる重要な権限ではあるため、APIキーの流出にはご注意ください。

これでmicroCMSの準備は完了です。

2. GA4からデータを取得する準備

次にGA4からデータを取得する準備を行います。
GA4からデータを取得するために、「Google Analytics Data API」を使用します。

似たような名前のAPIに「Google Analytics Reporting API」というものがありますが、こちらは2023年7月に終了したユニバーサルアナリティクスのデータを取得する場合に使用するものなので、ご注意ください。

2-1. Google Analytics Data APIの準備

Google Analytics Data APIの準備は、Google Cloud(以下、GC)上で作業を行うため、GCプロジェクトの作成をお願いします。

2-1-1. Google Analytics Data APIを有効化

Google Analytics Data APIを使用するには、Google Analytics Data APIを有効化する必要があります。

1. 作成したGCプロジェクトのヘッダーにある検索欄に「ライブラリ」と入力し、「ライブラリ(APIとサービス)」をクリックしてAPI ライブラリページにアクセス

2. API ライブラリページで「google analytics」と検索

3. 検索結果から「Google Analytics Data API」を選択し、「有効にする」ボタンをクリックしてGoogle Analytics Data APIを有効にする

これでGoogle Analytics Data APIを有効化することができました。

2-1-2. サービスアカウントの作成

次にGoogle Analyticsからデータを取得するためのサービスアカウントを作成します。

1. GCプロジェクトのヘッダーにある検索欄に「サービスアカウント」と入力し、「サービスアカウント(IAM と 管理)」をクリックしてサービスアカウントページにアクセス

2. サービスアカウントページの「+サービスアカウントを作成」をクリック

3. 「サービスアカウントID」にお好みのIDを設定し、完了をクリック

4. 作成したサービスアカウントを選択し、「キー」タブから新しい鍵を作成

5. キータイプで「JSON」を選択した状態で作成

これで秘密鍵の作成が完了し、JSONファイルがダウンロードされます。このファイルのデータを使用することでGoogle Analytics Data APIを使用することができます。

このJSONファイルのデータを使用することでGCのサービスを操作することができてしまうので、流出にはご注意ください。
これでGC上の操作は完了です。

2-2. GA4にサービスアカウントを追加

先ほど作成したサービスアカウントをGA4のユーザーとして追加して、GA4のデータにアクセスできるようにします。

1. 今回使用するGA4のプロパティを開き、「アカウントのアクセス管理」をクリック

2. 「ユーザーを追加」をクリック

3. 先ほどGCで作成したサービスアカウントのアドレスを入力して追加

役割は「閲覧者」で問題ありません。
これでGA4のデータにGCのサービスアカウントがアクセスできるようになりました。

このサービスアカウントでGoogle Analytics Data APIを使用することでGA4のPV数を取得することができます。

3. 集計スクリプトの作成

GA4からデータを取得する準備が完了したので、次に集計スクリプトを作成します。
今回は、以下の技術構成で集計スクリプトを作成します。

スクリプトの実行環境: AWS Lamda(Node.js)
定期実行: Amazon EventBridge
GA4のデータ取得: Google Analytics Data API

3-1. ローカルでライブラリの準備

Lamdaで関数を作成する前に使用するライブラリの準備をします。
Lamda関数はサイズに制限があるため、使用するライブラリを含むnode_modulesはLamdaレイヤーにアップします。

■Lamdaレイヤーとは?
AWS公式サイトでは以下のように説明されています。

Lambda レイヤーは、補助的なコードやデータを含む .zip ファイルアーカイブです。レイヤーには通常、ライブラリの依存関係、カスタムランタイム、または設定ファイルが含まれています。
引用元:レイヤーによるLamda依存関係の管理


複数のLamda関数間で同じライブラリを共有したり、Lamda関数とライブラリを分離してシンプルにする用途などで使用することができます。今回のように、ライブラリのサイズがLamda関数のサイズ制限を超えてしまう場合に、Lamdaレイヤーにライブラリをアップすることでサイズ制限の回避用途として使用することもできます。

今回使用する以下の2つのライブラリをインストールしてZIPに圧縮します。

@google-analytics/data:Google Analytics Data APIを扱うのに使用
jsdom:ランキング用のタイトルやサムネイルを取得するためのHTML解析に使用

1. ライブラリのインストール

npm install @google-analytics/data jsdom

2. 作成されたnode_modulesをZIPに圧縮

3. Lamdaレイヤーの作成から、圧縮したZIPファイルをアップロードしてレイヤーを作成

このレイヤーを次に作成するLamda関数で使用することで、ライブラリを扱えるようになります。

3-2. AWS Lamda関数の作成

PV数集計用のLamda関数を作成します。

1. Lamda関数を作成

2. 集計スクリプトをLamda関数のindex.mjsに作成

処理の流れとしては、以下のような形で実装します。

  1. Google Analytics Data APIを使用して、一定期間のPV数とそのURLを取得
  2. それぞれのURLにfetchしてmetaタグからページタイトルとog:imageを取得
  3. microCMSのコンテンツAPI(PATCH)でランキングデータを更新
import { BetaAnalyticsDataClient } from "@google-analytics/data";
import { JSDOM } from 'jsdom';

// Google Analytics Data API用クライアント作成
const analyticsDataClient = new BetaAnalyticsDataClient({
  projectId: process.env.ANALYTICS_PROJECT_ID,
  credentials: {
    // メールアドレスを環境変数から設定
    client_email: process.env.ANALYTICS_CLIENT_EMAIL,

    // 秘密鍵を環境変数から設定
    // 環境変数から読み込むと「\n」がただの文字列として判定されていまうため、replaceで改行に置換
    private_key: (process.env.ANALYTICS_PRIVATE_KEY || "").replace(/\\n/g, "\n"),
  },
});

export const handler = async (event) => {
  let status = 500;
  
  try {
    const [gaResponse] = await analyticsDataClient.runReport({
      // GA4のプロパティIDを環境変数から設定
      property: `properties/${process.env.ANALYTICS_PROPERTY_ID}`,
      // データ取得範囲を1日前から8日前まで(過去7日間)に設定
      dateRanges: [
        {
          startDate: "8daysAgo",
          endDate: "1daysAgo"
        }
      ],
      // 取得対象の指標をscreenPageViews(PV数)に設定
      metrics: [{ name: "screenPageViews" }],
      // hostNameとpagePathを基準に取得するように設定
      dimensions: [
        { name: "hostName" },
        { name: "pagePath" }
      ],
      // フィルターを設定(例)
      // フィルター設定はご自身の環境に置き換えてください
      dimensionFilter: {
        filter: {
          stringFilter: {
            // ページパスが /posts/から始まるページのみを対象にする
            value: "^\/posts\/.+$",
            matchType: "FULL_REGEXP"
          },
          fieldName: "pagePath"
        }
      },
      limit: 10 // 上位10件を取得
    });
    
    // meta情報(タイトルとアイキャッチ)を取得するためにfetchの準備
    let fetchList = [];
    for (const row of gaResponse.rows) {
      const url = "https://" + row.dimensionValues[0].value + row.dimensionValues[1].value;
      fetchList.push(fetch(url));
    }
    const fetchResult = await Promise.all(fetchList);

    // メタデータの取得
    const metaData = {};
    for (const result of fetchResult) {
      if (!result.ok) {
        continue;
      }

      // JSDOMを使用して、fetchしてきたデータのDOMを解析
      const html = await result.text();
      const dom = new JSDOM(html);
      const document = dom.window.document;


      // ogImageを取得
      const ogImage = document.querySelector('meta[property="og:image"]');
      
      // タイトルを取得
      const title = document.querySelector('title');


      // URLをキーにしたメタ情報のオブジェクトを作成
      const url = new URL(result.url);
      metaData["https://" + url.hostname + url.pathname] = {
        image: ogImage !== null ? ogImage.getAttribute("content") : "",
        title: title !== null ? title.textContent : ""
      };
    }

    // microCMSに送るデータを作成
    const resultData = gaResponse.rows.map((row) => {
      const url = "https://" + row.dimensionValues[0].value + row.dimensionValues[1].value;

      return {
        fieldId: "posts", // 1-1-1で作成したカスタムフィールドのID「posts」
        url: url,
        pv: Number(row.metricValues[0].value),
        title: metaData[url].title,
        eyecatch: metaData[url].image
      };
    });
    
    // microCMSのランキングAPIをPATCHで更新
    const microCmsResponse = await fetch(`https://${process.env.MICROCMS_SERVICE_DOMAIN}.microcms.io/api/v1/ranking`, {
      method: 'PATCH',
      headers: {
        'Content-Type': 'application/json',
        'X-MICROCMS-API-KEY': process.env.MICROCMS_API_KEY ?? ''
      },
      body: JSON.stringify({
        data: resultData // 1-1-1で作成したAPIスキーマ「data」
      })
    })
    
    status = 200;
  } catch(e) {
    console.error(e);
  }

  return {
    statusCode: status,
    body: status === 200 ? "success" : "error",
  };
};

analyticsDataClient.runReportで設定するdimensionsやフィルターは公式ドキュメントに記載されているので、他の条件にカスタマイズしたい方はそちらをご覧ください。


※スクリプト内で利用している環境変数については後述します。

3. 作成したLamda関数を開いた下にある、「レイヤーを追加」から先ほど作成した「ranking-node_modules」レイヤーを追加

4. Lamda関数の設定から環境変数を設定

それぞれGA4やmicroCMSで使うAPIキーなどを設定します。

ANALYTICS_CLIENT_EMAIL:2-1-1でダウンロードしたJSONのclient_email
ANALYTICS_PRIVATE_KEY:2-1-1でダウンロードしたJSONのprivate_key
ANALYTICS_PROJECT_ID:2-1-1でダウンロードしたJSONのproject_id
ANALYTICS_PROPERTY_ID:今回使用するGA4のプロパティID
MICROCMS_API_KEY:1-1-3で設定したmicroCMSのAPIキー
MICROCMS_SERVICE_DOMAIN:今回使用するmicroCMSのサービスドメイン(エンドポイント)

5. タイムアウト時間を3秒(デフォルト)から3分に設定

処理に3分以上かかる場合はそれ以上の時間を設定してください。

作成したLamda関数を実行し、microCMSのランキングページにデータが10件挿入されていれば作成完了です。

▼実行後のイメージ

3-2. AWS Lamda関数の作成

最後に毎週月曜日にLamda関数を実行させるために、Amazon EventBridgeの設定をします。

1. Amazon EventBridgeのスケジュールからスケジュールを作成

2. スケジュールのパターンを「定期的なスケジュール」にし、cron式に「0 0 ? * 1 *」を設定
「次の10個のトリガー」が毎週月曜日になっていることを確認する

3. ターゲットの選択でAWS Lamda Invokeを選択

4. Invokeに作成したLamda関数を設定

5. その他再試行の回数(デフォルト185回)などお好みで設定し、作成を完了

これでスケジュールの作成が完了し、PV数ランキングの作成は完了です。

4. フロントエンドにつなぎこみ

フロントエンド上でランキングを表示するために、microCMSのランキングデータを取得する必要があります。通常のmicroCMSのコンテンツと同様に、コンテンツAPIのGETメソッド /api/v1/ranking へアクセスすることでランキングデータを取得することができます。

今回はランキングAPIをオブジェクト形式で作成しているため、/api/v1/{endpoint}/{content_id} と同様のレスポンスが返ってきます。
GET /api/v1/{endpoint}/{content_id}|microCMSドキュメント

コンテンツAPIを使用してランキングデータを取得すると、以下のようなレスポンスが返ってきます。

{
    "createdAt": "0000-00-00T00:00:00.000Z",
    "updatedAt": "0000-00-00T00:00:00.000Z",
    "publishedAt": "0000-00-00T00:00:00.000Z",
    "revisedAt": "0000-00-00T00:00:00.000Z",
    "data": [ // ランキングデータ(PV数の多い順に並んでいる)
        {
            "fieldId": "posts",
            "title": "1番PV数が多い記事",
            "url": "https://example.com/post/1",
            "pv": 54321,
            "eyecatch": "https://images.microcms-assets.io/assets/xxxx/1111.jpg"
        },
        {
            "fieldId": "posts",
            "title": "2番目にPV数が多い記事",
            "url": "https://example.com/post/2",
            "pv": 321,
            "eyecatch": "https://images.microcms-assets.io/assets/xxxx/2222.jpg"
        },
        ... // 集計スクリプトで設定した件数分続く 
    ]
}

dataの値がランキングのデータになります。

格納されている配列のデータを順番に表示することで、PV数の多い順に記事を表示することができます。

おわりに

今回は、AWS Lamdaを利用した、Google Analytics 4と連携してJamstack構成のサイトでPV数ランキングを作る方法をご紹介しました。

ウェブサイト制作においてPV数ランキングの実装はよくあることだと思いますので、本記事が実装する際の参考になれば幸いです。

まずは、無料で試してみましょう。

APIベースの日本製ヘッドレスCMS「microCMS」を使えば、 ものの数分でAPIの作成ができます。

microCMSを無料で始める

microCMSについてお問い合わせ

初期費用無料・14日間の無料トライアル付き。ご不明な点はお気軽にお問い合わせください。

お問い合わせ

microCMS公式アカウント

microCMSは各公式アカウントで最新情報をお届けしています。
フォローよろしくお願いします。

  • X
  • Discord
  • github

ABOUT ME

岸本 彬
株式会社メンバーズ メンバーズルーツカンパニーにて主にフロントエンドエンジニアとして業務しています。最近はmicroCMSとAstroを使ったJamstack構成の開発を行っています。
株式会社メンバーズ 認定パートナー
運用で社会を変革するデジタルクリエイター集団です。弊社は、microCMSを活用して、国内金融企業さまへの『デジタル運用特化』でお客様のビジネス変革・成果向上の内製化を推進します。
https://www.members.co.jp/
制作を依頼する