ZendeskとGoogle Analytics 4のデータを統合してヘルプコンテンツ管理に役立てたい

この記事は、「ヌーラボブログリレー2025 冬」のTechブログ 23日目の記事です。
はじめに
今回は、ZendeskとGoogle Analytics 4(以下、GA4)のデータを統合してコンテンツ管理に役立てられないかということで、やったことを紹介したいと思います。タイトルを「役立てたい」としたのは、これといった正解は今の段階で見つかっていないためです。(道半ばではありますが、現時点での知見を共有します!)
ヘルプセンターのコンテンツにおいて「どの記事が本当に役立っているのか」「更新すべき記事はどれか」を客観的に判断するのは難しいです。新しい記事が増えるにつれて、管理することも難しくなっていきます。今回のことが、記事を更新する際の判断の一助になればと思いました。
よくある課題
先にも少し記載していますが、コンテンツの管理において、たとえば下記のような課題があると思います。
- 記事が蓄積されて、管理が困難になる
- 改善の余地がある記事が埋もれてしまう
- どの記事を優先的に更新すべきかの判断が難しい
手始めにやったこと
GA4を導入していることもあり、各記事のページビュー数やエンゲージメント率などを取得できる状態にはありました。そのGA4のデータを見にいくハードルを下げたかったため、Looker Studioを使ってダッシュボードをつくることを手始めに実施してみました。
ここではLooker Studioの利用方法は割愛しますが、ダッシュボードがあることによって注視する数値が絞れて、必要なデータだけが追えるようになります。これだけでもある程度の価値はあるかもしれませんが、GA4の数値だけではなかなかコンテンツ管理の判断軸としにくいところがあります。
Zendeskのデータも利用してGA4と組み合わせる
Zendeskでつくられたサイトではユーザー評価のデータを取得しています。記事のそのページ内で、その記事が役に立ったかどうかを「はい」か「いいえ」かで投票していただいています。
このZendeskのデータとGA4のデータを組み合わせてコンテンツ管理の判断軸としたいと考えました。ページビュー数の軸と、ユーザー評価の軸で区分けできるといいのかなと考えました。
横軸のページビュー数、縦軸をユーザー評価とします。どちらの軸も閾値をどこに設定するか次第ではありますが、ページビュー数はヘルプセンター全体のサイトの中央値より多いか少ないかを判断軸とします。ユーザー評価に関しても目標値によりますが、ここではプラス評価かマイナス評価かを判断軸とします。すると、4つの象限に区分けすることができます。ここでは第1〜第4象限と呼びます。

第1象限:比較的閲覧されていて、「役に立った」の回答数が多い
これは、よい記事といえると思うので、維持する必要があります。なにがよいのかを分析して知見を得たいと思いました。KEEPという名前でラベリングします。
第2象限:比較的閲覧されていないが、「役に立った」の回答数が多い
閲覧数だけをみると削除対象になりそうですが、一部の人の役には立っているパターンです。本当に削除していいのかは検討する必要があります。こちらはREVIEW_NICHEという名前でラベリングします。
第3象限:比較的閲覧されておらず、「役に立たなかった」の回答数が多い
ここは、あまり閲覧されていないこともあり、記事の削除も検討する必要があります。この記事を活かすなら大幅な編集が必要になるかもしれません。記事自体の役割が終わった可能性もあります。こちらはARCHIVE_CANDIDATEという名前でラベリングします。
第4象限:比較的閲覧されているが、「役に立たなかった」の回答数が多い
比較的よく見られているのに役に立っていないので、優先的に修正が必要な記事になります。こちらはREVIEW_QUALITYという名前でラベリングします。
APIでデータをとってくる
ここまでですでに記事をどうするかの検討事項が多い印象ですが、データ取得部分を一部抜粋して説明します。Node.jsで実装しました。
Zendeskからの記事取得
Zendesk Help Center APIのarticles.jsonエンドポイントを使用します。記事数は一度のリクエストで全件取得できないことが多いため、next_pageプロパティを確認しながらループ処理で取得するようにしました。
このAPIは、デフォルトで各記事の評価(vote_sum)や更新日時(updated_at)を含んだオブジェクトを返してくれます。URL末尾のinclude=users,sectionsは、追加で「作成者名」や「セクション名」を取得するためのオプションです。
// Zendesk APIから全記事を取得する例
async getAllArticles(locale = "ja") {
let articles = [];
let url = `${this.baseUrl}/help_center/${locale}/articles.json?include=users,sections`;
while (url) {
const response = await axios.get(url, { headers: this._getHeaders() });
const data = response.data;
// 記事データに、関連するユーザーとセクションの情報を付与する
const usersById = new Map(data.users.map(u => [u.id, u]));
const sectionsById = new Map(data.sections.map(s => [s.id, s]));
const enrichedArticles = (data.articles || []).map(article => {
return {
...article,
author: usersById.get(article.author_id),
section: sectionsById.get(article.section_id)
};
});
articles = articles.concat(enrichedArticles);
url = data.next_page; // 次のページがあればURLが入る
}
return articles;
}
GA4からの指標取得
Google Analytics Data APIを使用します。公式のライブラリ@google-analytics/dataを使い、ページパスごとのページビュー数やエンゲージメント率などを取得します。
// GA4 Data APIから指標を取得する例
async getPageMetrics(startDate, endDate) {
const [response] = await this.client.runReport({
property: `properties/${this.propertyId}`,
dimensions: [{ name: 'pagePath' }],
metrics: [
{ name: 'screenPageViews' },
{ name: 'userEngagementDuration' },
{ name: 'activeUsers' },
{ name: 'engagementRate' },
{ name: 'bounceRate' }
],
dateRanges: [{ startDate, endDate }]
});
// ... レスポンスの加工処理
return data;
}
データの結合とラベリング
取得したZendeskの記事データとGA4の指標データを、記事のURLをキーにして結合します。
そして、全記事の閲覧数の中央値を算出し、各記事が「中央値より上か下か」「評価が良いか悪いか」で先ほどの4つの象限にラベリングします。
// 判定ロジックの実装例
_getRecommendation(row, medianViews) {
const views = row.views;
const voteSum = row.vote_sum; // 評価の合計(役に立った - 役に立たなかった)
// PV多 (中央値以上)
if (views >= medianViews) {
if (voteSum < 0) {
return "REVIEW_QUALITY (第4象限: PV多・低評価)";
}
return "KEEP (第1象限: PV多・高評価)";
}
// PV少 (中央値未満)
if (voteSum < 0) {
return "ARCHIVE_CANDIDATE (第3象限: PV少・低評価)";
}
return "REVIEW_NICHE (第2象限: PV少・高評価)";
}
この処理によって、記事ごとに具体的なアクションが自動的に割り振られます。
データをスプレッドシートに出力する
分析してラベリングした結果は、google-spreadsheetパッケージを使ってGoogleスプレッドシートに直接書き出しています。CSV出力でも良いですが、スプレッドシートに出力することで、チームメンバーとリアルタイムに共有・編集ができるようになります。
// 分析結果をシートに書き込む例
async updateSheet(header, data) {
const doc = new GoogleSpreadsheet(this.sheetId, this.auth);
await doc.loadInfo();
const sheet = doc.sheetsByIndex[0];
// シートをクリア
await sheet.clear();
// ヘッダーを設定(日本語のタイトルを使用)
const headerTitles = header.map(h => h.title);
await sheet.setHeaderRow(headerTitles);
// データをヘッダーのタイトルに合わせた形式に変換
const formattedData = data.map(row => {
const newRow = {};
header.forEach(h => {
// スプレッドシートの列名(日本語)に合わせてデータをマッピング
newRow[h.title] = row[h.id];
});
return newRow;
});
await sheet.addRows(formattedData);
}
これにより、スクリプトを実行するだけで最新の分析結果がシートに反映されます。
作成したテーブル
項目の取捨選択をして、現在は以下のようなカラムを持つテーブルが出力されるようにしています。なお、このリストは修正の優先度が高い順(REVIEW_QUALITY → ARCHIVE_CANDIDATE → REVIEW_NICHE → KEEP)に並べ替えています。
- タイトル: 記事のタイトル
- URL: 記事のURL
- 推奨アクション: 分析結果に基づいた4象限の分類(REVIEW_QUALITYなど)
- 評価合計: 「役に立った」から「役に立たなかった」を引いたスコア
- 閲覧数: 指定期間内のページビュー数
- エンゲージメント率: ユーザーがエンゲージメントを行ったセッションの割合
- エンゲージメント時間: ユーザーが記事を閲覧していた平均時間
- 直帰率: エンゲージメントが発生しなかったセッションの割合
- 更新日時: 記事が最後に更新された日時
この出力されたスプレッドシートをデータソースとして、Looker Studioで可視化しています。
このテーブルをどうみていくか
先にも述べたように、閾値をどこに置くかによってラベリングも変わってきます。
ラベルだけをみて記事の扱いを決めることは難しいので、たとえばエンゲージメント率が低いところのセルに色付けしたり、更新日時が昔のもののセルに色付けしたりして、検討材料になりそうな数値に目印をつけています。
成果と今後の課題
機能アップデートにあわせて記事を修正したり、お問い合わせをベースにコンテンツを見直したりすることは、ヘルプコンテンツのチームで進められていて頼もしい限りです。今回作成したテーブルは、不要なコンテンツに気づいて削減し、管理しやすくなる点においては、ある程度役に立つかなと思います。
一つの表に落とし込むことはできるものの、具体的にどこをどのように修正すればいいのかまでは数字だけでは見えてきません。実際の記事を目視したり、Microsoft Clarityなどのヒートマップツールでユーザー行動を追ったりする必要性を感じました。
また、ユーザー評価そのものはとても大事な指標なのですが、評価数の変動が大きくないため、これを判断材料としていることへの難しさも感じています。
おわりに
繰り返しにはなりますが、ZendeskとGA4の数値だけをみて判断することは難しく、さらに別のツールを見にいくことも必要だというところに落ち着きました。このデータをみれば一目瞭然ネクストアクションがわかる、というところまで到達するには、さらなる分析や工夫が必要になると思います。
とはいえ、今回のやり方は最初の一歩としては悪くないとも思います。ZendeskとGA4の組み合わせなら他にもやり方はあるはずですが、今回のようにVibe Codingで時間をかけずに作りきることもできます。
多くの企業がヘルプセンターやナレッジベースを運営していると思うので、どのようにコンテンツ管理しているのかに関して、とても興味が湧いています。引き続き最適なコンテンツ管理について考えていきたいと思います。
Discussion