GA4のAPIとGitHub Actionsを使って人気記事を自動更新する
このブログに人気記事一覧を表示させるようにしてみました。
毎朝9時に自動更新される仕組みです。
本記事ではその方法を詳細に説明していきます。
前提
- コンテンツ管理にはmicroCMSを利用している
- アナリティクスにはGoogle Analytics 4を利用している
- ソースコードをGitHubで管理している
- フロントエンドはSSGしている
全体の流れ
- Analytics Data APIを用いて記事のPV情報を取得する
- PV上位10件をmicroCMSに保存する
- サイトをビルド&デプロイし、人気記事一覧を更新する
- 1〜3の処理をGitHub Actionsのcronを用いて毎朝9時に自動実行する
Google Analyticsから情報を取得する
GA4から情報を取得するためには、Analytics Data APIを用います。
そのためにGoogle Cloud Platform(GCP)のアカウントが必要です。これは各自用意してください。
次にGCPのプロジェクトを作成します。
その後、「APIとサービス > 有効なAPIとサービス」からGoogle Analytics Data APIを見つけ、有効化しましょう。
そして、「認証情報を作成」ボタンをクリックします。
認証情報としてサービスアカウントを作成します。次のように進めていきます。
以上でサービスアカウントが作成されます。
次に、サービスアカウントキーをJSON形式でダウンロードします。
以上でGCP側の準備は完了です。
今度はGoogle Analyticsに移動し、「設定 > プロパティのアクセス管理 > ユーザーを追加」から先ほど作成したサービスアカウントのメールアドレスを追加します。
これにより、サービスアカウントの認証を使って自身のGoogle Analyticsのデータを読み取ることができるようになりました。
PV上位10件を取得し、microCMSに保存する
本ブログはCloudflareにホスティングしているので、データの保存先としてWorkers KVやD1などを使ってみたかったんですが、エッジ上でAnalytics Data APIが動かず断念しました・・・。
(NodeのAPIを使わず素で呼び出そうと頑張ったんですが、認証周りが厳しそうだったので諦めました)
というわけで、元々コンテンツ管理としても利用しているmicroCMSにデータを保存することにしました。
microCMS側の設定
PVランキングを保存するための箱をmicroCMSに用意します。
今回はpopularというAPIを作成しました。
リスト形式で作成します。
オブジェクト形式で作成しても良いのですが、実は裏技的なテクニックがありまして。
本ブログにはRanking(自動)とPickup(手動)という2種類の枠を用意しており、その両方をpopularという一つのAPIで管理してしまおうという作戦です。
APIスキーマは、別APIとして管理しているブログAPIを複数コンテンツ参照します。
以上でAPIの準備は完了です。
次にコンテンツIDをranking
として、ランキング管理用のコンテンツを作成して公開しておきます。
最後にこのコンテンツに対してAPIから書き換えを行うためにAPIキー設定にてPATCH
を許可します。
本来、GET
とPATCH
のキーは分けるべきですが、HobbyプランでAPIキーを1つしか作れないのでやむなし・・・。
SSGかSSRでAPIキーが秘匿されるようにしましょう。
これでmicroCMS側の準備は完了です。
コード側
次はコード側を進めていきます。
まずは下記2つのパッケージをインストールします。
npm install @google-analytics/data microcms-js-sdk
そして、実際にPVを取得してmicroCMSに書き込む処理はこちら。
後のGitHub Actionsでの処理も考慮して、.github/actions/ranking/index.js
というファイルを作成します。
import { BetaAnalyticsDataClient } from '@google-analytics/data';
import { createClient } from 'microcms-js-sdk';
const client = createClient({
serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
apiKey: process.env.MICROCMS_API_KEY
});
const serviceAccountKey = JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT_KEY || '');
const analyticsDataClient = new BetaAnalyticsDataClient({
credentials: {
client_email: serviceAccountKey.client_email,
private_key: serviceAccountKey.private_key,
},
});
export const getPopularArticles = async () => {
const [response] = await analyticsDataClient.runReport({
property: `properties/${process.env.GA_PROPERTY_ID}`,
dateRanges: [
{
startDate: '8daysAgo',
endDate: '1daysAgo',
},
],
dimensions: [
{
name: 'pagePath',
},
],
metrics: [
{
name: 'screenPageViews'
}
],
// トップページ(/)を除く
dimensionFilter: {
filter: {
fieldName: 'pagePath',
stringFilter: {
matchType: 'FULL_REGEXP',
value: '^/[^/]+$',
},
},
},
limit: '10',
});
const data = response.rows?.map(row => {
return {
path: row.dimensionValues?.[0].value,
views: row.metricValues?.[0].value
}
});
return data;
};
const popularArticles = await getPopularArticles() || [];
const ids = popularArticles.map((article) => article.path.slice(1));
await client
.update({
endpoint: 'popular',
contentId: 'ranking',
content: {
articles: ids,
},
});
本ブログの場合は/xxxxxx
というURLパスのPVをカウントしたかったため、dimensionFilter
ではそのような正規表現を書いています。
limit
の部分で上位何件分を取得するか決定しているので、適宜変更してください。
環境変数
Analytics Data API、Google Analytics、microCMS APIに必要な認証情報は環境変数で管理しています。
GOOGLE_SERVICE_ACCOUNT_KEY
先ほどダウンロードしてきたサービスアカウントキーのJSONデータをそのまま文字列として環境変数に突っ込んでいます。
GA_PROPERTY_ID
Google AnalyticsのプロパティIDです。「管理 > プロパティ」で確認できます。
MICROCMS_SERVICE_DOMAIN
microCMS管理画面URLのxxxxxx.microcms.io
のxxxxxx
の部分です。
MICROCMS_API_KEY
microCMSのAPIキーです。「サービス設定 > APIキー」で確認できます。
GitHub Actionsのcronを用いて毎朝9時に自動実行する
これまでの処理をGitHub Actionsで実行します。
先ほど作成した.github/actions/ranking/index.js
というファイルに加えて、.github/workflows/ranking.yml
を用意します。
name: Set Ranking
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
set-ranking:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/[email protected]
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Set Ranking
env:
GOOGLE_SERVICE_ACCOUNT_KEY: ${{secrets.GOOGLE_SERVICE_ACCOUNT_KEY}}
GA_PROPERTY_ID: ${{secrets.GA_PROPERTY_ID}}
MICROCMS_API_KEY: ${{secrets.MICROCMS_API_KEY}}
MICROCMS_SERVICE_DOMAIN: ${{secrets.MICROCMS_SERVICE_DOMAIN}}
run: node ./.github/actions/ranking
- name: Publish to Cloudflare Pages
run: curl -X POST "https://api.cloudflare.com/client/v4/pages/webhooks/deploy_hooks/${{ secrets.CLOUDFLARE_DEPLOY_HOOK }}"
まずはトリガー部分ですが、cronを使って毎朝9時に定期的に発火されるようにします。
(UTCで0時0分なので、日本時間だと朝9時になります)
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
ちなみに動かしてみると1時間くらい発火がズレて、朝10時くらいに動き出します。
workflow_dispatch
と記述しておくと、GitHub Actionsの管理画面から手動でも動かせるので便利です。
そして、.github/actions/ranking/index.js
を動かす部分ですが、環境変数の設定が必要です。
GitHubの設定画面からSecretsの設定ができるので、そこで先ほどの4つの環境変数をセットします。
加えて、記事ランキングの更新を本番反映させるために、最後にCloudflareへのビルド&デプロイをしたいので、CloudflareのビルドフックのID部分も環境変数にしています。
(ここは記事ランキングを管理しているmicroCMS側からWebhookで発火しても良さそうです)
お疲れ様でした。以上で準備は完了です。
ソースコードをPUSHして、無事に動くかどうか試してみましょう。
(ちなみにcronはmainブランチでないと動かないらしいです)
下記のように動作していれば成功です。
おわりに
かなり長い記事になってしまいましたが、詳細に手順を紹介できました。
環境によって少しずつ変更点はあると思いますが、microCMSを利用している環境であれば、だいたい同じような感じで動かすことができると思います。
自動的にデータが更新されるのは気持ち良いので、ぜひお試しあれ!