HugoとGoogle Analyticsを使って人気記事のランキングを作る方法を紹介します
ステップとしては
- GCPから鍵を作成し、Google Analyticsで権限を付与
 - Google Analytics Data APIからpv数を取得するスクリプトを作成
 - 保存したpvデータを元にHugoからランキング作成
 - CIで定期的にpv取得スクリプトを起動させる
 
1. GCPから鍵を作成し、Google Analyticsで権限を付与
基本的にはdevelopers IOさんの記事を参考にします。「Google Analyticsでサービスアカウント用のユーザーに権限を与える」の部分まで実行してください。
2020年10月以降はGA4が使われるようになったので「Google Analytics Data API」を使います。そちらを有効にしてください。
アナリティクス Reporting API v4を使ってGoogle Analyticsのデータを取得する
2. Google Analytics Data APIからpv数を取得するスクリプトを作成
まずは必要なnpmライブラリをinstallします
npm install @google-analytics/data
npm install dayjs
次にpv取得スクリプトを作成します。propertyIdにはgoogle analyticsのプロパティIDを、process.env.GOOGLE_APPLICATION_CREDENTIALSには上記の記事で作成したcredentialsファイルを指定します。
scripts/create-ranking.js
try {
    /**
     * TODO(developer): Uncomment this variable and replace with your
     *   Google Analytics 4 property ID before running the sample.
     */
    propertyId = '286243825'
    process.env.GOOGLE_APPLICATION_CREDENTIALS = `.gcp/google-analytics_credentials.json`
    // Imports the Google Analytics Data API client library.
    const dayjs = require('dayjs')
    const utc = require('dayjs/plugin/utc.js')
    const timezone = require('dayjs/plugin/timezone.js')
    const fs = require('fs')
    const { BetaAnalyticsDataClient } = require('@google-analytics/data')
    dayjs.extend(timezone)
    dayjs.extend(utc)
    dayjs.tz.setDefault('Asia/Tokyo')
    // Using a default constructor instructs the client to use the credentials
    // specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
    const analyticsDataClient = new BetaAnalyticsDataClient()
    // Runs a simple report.
    async function runReport() {
        const [response] = await analyticsDataClient.runReport({
            property: `properties/${propertyId}`,
            dateRanges: [
                {
                    startDate: '8daysAgo',
                    endDate: '1daysAgo',
                },
            ],
            dimensions: [
                {
                    name: 'pagePath',
                },
            ],
            metrics: [
                {
                    name: 'screenPageViews',
                },
            ],
        })
        let rankings = []
        response.rows.forEach((row) => {
            rankings.push({
                pagePath: row.dimensionValues[0].value,
                pv: row.metricValues[0].value,
            })
        })
        fs.writeFileSync(
            'data/ranking.json',
            JSON.stringify(
                {
                    items: rankings,
                    createdAt: dayjs().toISOString(),
                },
                null,
                4
            )
        )
    }
    runReport()
} catch (error) {
    console.error(error)
}
GA4向けのGoogle Analytics Data APIのドキュメントTOP
https://developers.google.com/analytics/devguides/reporting/data/v1
Google Analytics Data APIクイックスタート
https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart-client-libraries
dimensions(寸法)一覧
https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema#dimensions
metrics(指標)一覧
https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema#metrics
package.jsonのscriptsに追記します
  "scripts": {
    "create-ranking": "node scripts/create-ranking.js"
そしてnpm run create-rankingを実行するとdataディレクトリに下記のようなjsonが出力されます
ranking.json
{
    "items": [
        {
            "pagePath": "/",
            "pv": "49"
        },
        {
            "pagePath": "/article/salt/about/",
            "pv": "14"
        },
        {
            "pagePath": "/article/hugo/archive/",
            "pv": "11"
        },
        ...
    ],
    "createdAt": "2022-01-12T08:46:12.008Z"
}
3. 保存したpvデータを元にHugoからランキング作成
{{ $ranking := slice }}
{{ range $item := sort .Site.Data.ranking.items "pv" "desc" }}
    {{ with $page := $.Site.GetPage (path.Clean $item.pagePath) }}
        {{ if eq .Section "article" }}
            {{ $ranking = $ranking | append (dict "page" $page "pv" $item.pv) }}
        {{ end }}
    {{ end }}
{{ end }}
{{ $ranking }}
{{ $ranking }}を展開してみるとこのようなmapになるのであとは表示するだけです
[
    map[page:Page(/article/salt/about/index.md) pv:14] 
    map[page:Page(/article/hugo/archive/index.md) pv:11] 
    map[page:Page(/article/salt/custom-figure/index.md) pv:8] 
    map[page:Page(/article/hugo/tips/index.md) pv:6] 
    map[page:Page(/article/salt/self-blog-card/index.md) pv:5] 
    map[page:Page(/article/sample/hugo-shortcode/index.md) pv:4] 
    map[page:Page(/article/hugo/search/index.md) pv:3] 
    map[page:Page(/article/go/go-template/index.md) pv:2] 
    map[page:Page(/article/go/variable/index.md) pv:2] 
    map[page:Page(/article/hugo/about/index.md) pv:2] 
    map[page:Page(/article/sample/markdown/index.md) pv:2] 
    map[page:Page(/article/hugo/fontawsome/index.md) pv:1]
]
4. CIで定期的にpv取得スクリプトを起動させる
あとは週一でCIを実行させればOK。
GitHub Actions
gcpからDLした鍵の内容をGitHubのsercretsにGOOGLE_ANALYTICS_CREDENTIALSとして保存してください。
.github/workflows/create_ranking.yml
name: Create Ranking
on:
  schedule:
    - cron: '0 0 * * 0'
jobs:
  deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
      - name: Setup npm
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - name: npm Install
        run: |
          npm ci
      - name: Create Ranking
        env:
          GOOGLE_ANALYTICS_CREDENTIALS: ${{ secrets.GOOGLE_ANALYTICS_CREDENTIALS }}
        run: |
          mkdir .gcp
          echo "$GOOGLE_ANALYTICS_CREDENTIALS" > .gcp/google-analytics_credentials.json
          npm run create-ranking
      - name: Commit and Push
        run: |
          git branch
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git commit -am "Create Ranking"
          git push origin HEAD
GitLab CI
GitLabのプロジェクトを選択し、設定 > CI/CD > 変数に下記を設定
GITLAB_USER_EMAILはGitLabで使っているemailGITLAB_USER_NAMEはGitLabで使っているuser nameSSH_PRIVATE_KEYはGitLab CIからpushする用のssh keyGOOGLE_ANALYTICS_CREDENTIALSはGCPから落としてきた鍵の中身
SSH_PRIVATE_KEYはssh-keygenコマンドから作成した秘密鍵をセットしてください
mkdir ./.ssh
ssh-keygen
> ./.ssh/gitlab_id_rsa
> Enter
> Enter
Your identification has been saved in .ssh/gitlab_id_rsa
Your public key has been saved in .ssh/gitlab_id_rsa.pub
GitLabのユーザー設定 > SSH鍵に公開鍵を登録するのをお忘れなく!
.gitlab-ci.yml
stages:
  - build
  - deploy
variables:
  GIT_SUBMODULE_STRATEGY: recursive
create-ranking:
  timeout: 5m
  stage: build
  image: node:20
  before_script:
    - eval `ssh-agent`
    - ssh-add <(echo "$SSH_PRIVATE_KEY")
    - mkdir .gcp
    - echo "$GOOGLE_ANALYTICS_CREDENTIALS" > .gcp/google-analytics_credentials.json
  script:
    - git config --global user.email $GITLAB_USER_EMAIL
    - git config --global user.name $GITLAB_USER_NAME
    - git remote set-url origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
    - git checkout $CI_COMMIT_REF_NAME
    - npm ci
    - npm run create-ranking
    - git add ./data
    - git commit -am "Create Ranking"
    - git -c core.sshCommand="ssh -oStrictHostKeyChecking=no" push origin ${CI_COMMIT_REF_NAME}
  only:
    - schedules
pages:
  timeout: 5m
  stage: deploy
  image: node:20
  script: |
    npm ci
    npm run build
  artifacts:
    paths:
      - public
  only:
    - main
最後にCI/CD > スケジュールから新規スケジュールを追加してください