ワイドコースのアプリ分析ツールに、Googleアナリティクスを連携してアクセス情報を反映してみよう

著者名:Nguyen Van Hai, hato( サイボウズ株式会社 (External link)

目次

information

本記事はワイドコースでのみ利用できる、専用機能を使います。
ワイドコースとは (External link)

はじめに

ワイドコースには、大規模利用向けの専用機能がいくつか用意されています。
たとえば、複数組織でアプリ作成が活発に行われると、アプリの棚卸や統制管理が重要になります。
そこで、ワイドコースで利用できる「アプリ分析」ツールを利用すると、各アプリの特徴や権限設定、アプリ間の関連を容易に分析できます。

ただし、既存のアプリ分析ツールでは、ページビュー数やユニークユーザー数の分析まではできません。

本記事では、ワイドコースのアプリ分析ツールとGoogleアナリティクス(以下GA)を連携し、ページビュー数やユニークユーザー数をアプリに反映する、Node.jsスクリプトの開発方法を紹介します。

想定読者

  • ワイドコースを利用中のシステム管理者
  • ワイドコースに興味があるシステム管理者
  • ワイドコースを提案、または専用機能のカスタマイズを行うパートナー

完成イメージ

アプリ分析ツールで利用できる「アプリ分析結果」アプリに、GAから取得した直近1ヵ月のページビュー数とユニークユーザー数を表示します。
アプリごとに実際の利用状況を分析できます。

GAデータの活用例

取得したページビュー数やユニークユーザー数を活用することで、次のような運用改善が可能です。

  • ページビュー数が一定以上のアプリのみを棚卸し対象とすることで、実際に利用されているアプリの把握や管理工数の削減ができます。
  • 利用頻度の低いアプリを抽出し、統合・削除・改善の検討材料にできます。
  • ユーザー数の多いアプリを重点的にサポート・改善するなど、運用方針の決定に役立ちます。

下準備

Node.js のインストール

Node.jsスクリプトを実行する環境に、Node.jsの最新のLTS版をダウンロードしてください。
Node.js (External link)

kintoneアプリの準備

「アプリ分析結果」アプリに、次のフィールドを追加してください。

フィールド名 フィールドタイプ フィールドコード 説明
GA分析開始日 日付 ga_start_date GAのデータ収集期間の開始日
GA分析終了日 日付 ga_end_date GAのデータ収集期間の終了日
合計ページビュー数 数値 ga_screen_page_views データ収集期間中にユーザーがアプリを閲覧した回数
合計ユニークユーザー数 数値 ga_total_users データ収集期間中にアプリを訪れたユニークユーザー数

アプリ分析ツールの実行

アプリ分析ツールをまだ利用していない場合は、まずツールを実行してください。
「アプリ分析結果」アプリにレコードが登録されていることを確認したうえで、本記事のカスタマイズを進めてください。

アナリティクスの設定

はじめに、kintoneのアクセス情報をGAに送信するための設定をします。
アナリティクスのアカウントをお持ちでない場合は アナリティクス (External link) から、アカウントの作成をしてください。

プロパティの作成

プロパティの作成方法は、次のページを参考にしてください。
[GA4] アナリティクスで新しいウェブサイトまたはアプリのセットアップを行う (External link)

プロパティの作成時の必須項目は、次のとおりです。

  • データの収集で、「ウェブ」を選択します。
  • ウェブストリームの設定のウェブサイトのURLは、kintoneのドメイン名を入力します。
    例:sample.cybozu.com
  • 作成したストリームを選択すると、G-で始まる「測定ID」が表示されます。
    コピーしてメモをします。

Googleタグの設定

Googleタグを設定するために「gtag.js」ファイルを作成します。
次のコードをコピーして、YOUR_MEASUREMENT_IDの箇所を、先ほどメモした「測定ID」に書き換え保存します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
 * gtag sample program
 * Copyright (c) 2025 Cybozu
 *
 * Licensed under the MIT License
 * <https://opensource.org/license/mit/>
 */
(function() {
    const MEASUREMENT_ID = 'YOUR_MEASUREMENT_ID';

    // Googleタグマネージャー用のscript要素を作成
    var gtagScript = document.createElement('script');
    gtagScript.async = true;
    gtagScript.src = `https://www.googletagmanager.com/gtag/js?id=${MEASUREMENT_ID}`;

    // 最初のscriptタグの前に挿入
    var firstScript = document.getElementsByTagName('script')[0];
    if (firstScript && firstScript.parentNode) {
      firstScript.parentNode.insertBefore(gtagScript, firstScript);
    } else {
      // scriptタグが見つからない場合はhead要素に追加
      document.head.appendChild(gtagScript);
    }

    // dataLayerとgtag関数を初期化
    window.dataLayer = window.dataLayer || [];
    function gtag() {
      window.dataLayer.push(arguments);
    }

    // gtagの初期設定を実行(グローバルで利用できるようwindowに設定)
    window.gtag = gtag; 

    window.gtag('js', new Date());
    window.gtag('config', MEASUREMENT_ID);
})();

kintone全体のカスタマイズで「gtag.js」を以下の設定で適用します。

  • カスタマイズの適用範囲を「すべてのユーザーに適用」
  • PC用とスマートフォン用のJavaScriptに「gtag.js」を追加

kintone全体のカスタマイズの適用方法は JavaScriptやCSSを使用したkintone全体のカスタマイズ (External link) を参照してください。

kintoneとアナリティクスの接続確認

「アプリ分析結果」アプリに登録されている、アプリを閲覧した後 アナリティクス (External link) を開きます。
「レポート」から「リアルタイムページ」をクリックすると過去30分間のアクティブユーザー数や視聴回数が表示されているのを確認できます。

information

GAのデータは、利用可能になるまで遅延する場合があります。
詳細については [GA4] データの更新頻度 (External link) を参照してください。

以上で、kintoneのアクセス情報をGAに送信するための設定は完了です。

GoogleアナリティクスData APIの設定

次に、GoogleアナリティクスData APIの設定をします。
設定をすることで、GAのレポートデータにプログラムからアクセスできます。
今回は、Node.jsスクリプトからアクセスするために利用します。

詳細については Google アナリティクス Data API の概要 (External link) を参照してください。

GoogleアナリティクスData APIを有効にする

Google Cloud プラットフォーム (External link) から設定します。
既存のプロジェクトを選択するか、新しいプロジェクトを作成して選択します。
プロジェクトの作成からする場合は Google Cloud プロジェクトを作成する (External link) を参照してください。

プロジェクトを選択後、画面上部の検索窓で「Google Analytics Data API」と検索します。
「Google Analytics Data API」の画面で[有効にする]をクリックします。

以上で、GoogleアナリティクスData APIの設定は完了です。

認証設定

GoogleアナリティクスData APIを有効にした後、実際に使用するためには、サービスアカウントを作成する必要があります。
サービスアカウントは、アカウント固有のメールアドレスで識別されます。
サービスアカウントを使用して、GAのデータに安全かつ自動的にアクセスできます。

詳細については サービス アカウントとは (External link) を参照してください。

サービスアカウントを作成する

サービス アカウント (External link) からプロジェクトを選択し、必要項目を入力してサービスアカウントを作成します。
詳細な手順は サービス アカウントを作成する (External link) のコンソール部分を参照してください。

サービスアカウントを作成すると、次の画像のようにリストで表示されます。

作成されたサービスアカウントをクリックすると、サービスアカウントの詳細が表示されます。
後で使用するため、「メール」をコピーしてメモします。

サービスアカウントキーを作成する

サービスアカウントをプログラムから利用するためには、鍵を作成してダウンロードする必要があります。
「鍵」のタブを開きます。[キーを追加]をクリックし、[新しい鍵を作成]をクリックします。

ダイアログが開くので「JSON」を選択し[作成]をクリックすると、鍵がダウンロードされます。
ダウンロードされたファイル名を「g4-key.json」に変更します。

GAでサービスアカウントに権限を付与する

サービスアカウントに、GAのプロパティにアクセスできる権限を付与する必要があります。
これにより、プログラムがGAのデータを取得する際に、適切な認証と承認が行われます。

次の手順で権限を付与します。

  1. アナリティクス (External link) にアクセスし、左下の[管理]をクリックして管理者画面に移動します。

  2. アカウント設定項目で[アカウントのアクセス管理]をクリックします。

  3. 右上の追加アイコンを選択し、[ユーザーを追加]をクリックします。

  4. 「役割とデータ制限の追加」画面が表示されるので「メールアドレス」の項目に サービスアカウントを作成する で作成したメールアドレスを入力します。
    「直接の役割とデータ制限」項目は「閲覧者」以上の権限を選択します。
    権限の詳細は [GA4] アクセス権とデータ制限の管理 (External link) を参照してください。

  5. 右上の[追加]をクリックします。

以上で、認証設定は完了です。

Node.jsスクリプトの作成

最後に、Node.jsスクリプトを作成します。
次のディレクトリと空のファイルを作成します。

1
2
3
4
5
6
sample-program
├── package.json
├── config.js
├── g4-key.json
├── utils.js
└── index.js

「g4-key.json」は サービスアカウントキーを作成する で作成したファイルを配置します。

必要なライブラリをインストールする

「package.json」に次の内容を記載します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "name": "kintone-ga4",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index"
  },
  "type": "module",
  "author": "Cybozu",
  "license": "MIT",
  "dependencies": {
    "@google-analytics/data": "^5.1.0",
    "@kintone/rest-api-client": "^5.7.4"
  }
}

ターミナルを開き「sample-program」ディレクトリでnpm installを実行し、必要なライブラリをインストールします。

スクリプトファイルの作成

次の3つのファイルを作成していきます。

  • index.js
  • utils.js
  • config.js
index.jsの作成

GA4のデータを取得して、kintoneに登録するメイン処理を実行するファイルです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/*
 * ga integration sample program
 * Copyright (c) 2025 Cybozu
 *
 * Licensed under the MIT License
 * <https://opensource.org/license/mit/>
 */
import {CONFIG} from './config.js';
import {ConfigValidator, GA4Service, KintoneService, CustomError} from './utils.js';

class ReportGenerator {
  constructor(analyticsData) {
    this.data = analyticsData;
  }

  calculateAppMetrics() {
    const appIdRegex = /\/k(?:\/m)?\/([0-9]+)/;

    return this.data.rows.reduce((metricsPerAppMap, row) => {
      const pagePath = row.dimensionValues[0].value;

      const appIdMatch = pagePath.match(appIdRegex);
      if (!appIdMatch) return metricsPerAppMap;

      const [_, appId] = appIdMatch;

      const [screenPageViews, totalUsers] = row.metricValues.map(metric => Number(metric.value));
      const previousScreenPageViews = metricsPerAppMap.get(appId)?.screenPageViews || 0;
      const previousTotalUsers = metricsPerAppMap.get(appId)?.totalUsers || 0;

      metricsPerAppMap.set(appId, {
        screenPageViews: previousScreenPageViews + screenPageViews,
        totalUsers: Math.max(previousTotalUsers, totalUsers),
      });

      return metricsPerAppMap;
    }, new Map());
  }
}

async function runReport() {
  try {
    const configValidationResult = ConfigValidator.validateConfig();
    if (configValidationResult.isValid === false) {
      console.log(`Validation error: ${configValidationResult.message}`);
      return;
    }

    const ga4Service = new GA4Service();
    const kintoneService = new KintoneService();

    const formFields = await kintoneService.getFormFields();
    const formFieldsValidationResult = ConfigValidator.validateFormFields(formFields, CONFIG);
    if (formFieldsValidationResult.isValid === false) {
      console.log(`Validation error: ${formFieldsValidationResult.message}`);
      return;
    }

    const analyticsData = await ga4Service.fetchAnalyticsData();
    const reportGenerator = new ReportGenerator(analyticsData);
    const appMetricsSummary = reportGenerator.calculateAppMetrics();

    if (appMetricsSummary.size === 0) {
      console.log('No app metrics found in GA for the specified date range.');
      return;
    }

    const analyzedAppIds = Array.from(appMetricsSummary.keys());
    const existingAppsInAAR = await kintoneService.getExistingApps(analyzedAppIds);

    await kintoneService.updateRecords(appMetricsSummary, existingAppsInAAR);
  } catch (error) {
    if (error instanceof CustomError) {
      console.error(error.message);
    } else {
      console.error(`Something went wrong: ${error}`);
    }
  }
}

runReport();
utils.jsの作成

GA4とkintoneのAPI操作や設定チェック、日付整形などの機能をまとめたファイルです。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
 * ga integration sample program
 * Copyright (c) 2025 Cybozu
 *
 * Licensed under the MIT License
 * <https://opensource.org/license/mit/>
 */
import {BetaAnalyticsDataClient} from '@google-analytics/data';
import {KintoneRestAPIClient} from '@kintone/rest-api-client';
import {CONFIG, DEFAULT_CONFIG} from './config.js';
import fs from 'fs';

export class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = 'CustomError';
  }
}

export class DateFormatter {
  static formatDate = (date) => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  };
}

export class GA4Service {
  constructor() {
    this.client = new BetaAnalyticsDataClient({keyFile: CONFIG.ga4.keyFilePath || DEFAULT_CONFIG.ga4.keyFilePath});
  }

  async fetchAnalyticsData() {
    try {
      const [response] = await this.client.runReport({
        property: `properties/${CONFIG.ga4.propertyId}`,
        dateRanges: [
          {
            startDate: CONFIG.dateRange.startDate || DEFAULT_CONFIG.dateRange.startDate,
            endDate: CONFIG.dateRange.endDate || DEFAULT_CONFIG.dateRange.endDate,
          },
        ],
        dimensions: [{name: 'pagePath'}],
        metrics: [{name: 'screenPageViews'}, {name: 'totalUsers'}],
      });

      console.log('The analysis results from GA have been successfully fetched.');

      return response;
    } catch (error) {
      throw new CustomError(`Error fetching data from GA: ${error.message}`);
    }
  }
}

export class KintoneService {
  constructor() {
    this.client = new KintoneRestAPIClient({
      baseUrl: CONFIG.kintone.baseUrl,
      auth: {apiToken: CONFIG.kintone.apiToken},
    });
  }

  async getFormFields() {
    const response = await this.client.app.getFormFields({
      app: CONFIG.kintone.appId,
    });
    return response.properties;
  }

  async getExistingApps(analyzedAppIds) {
    const response = await this.client.record.getAllRecords({
      app: CONFIG.kintone.appId,
      condition: `app_id in (${analyzedAppIds.join(',')})`,
    });
    return response.map((record) => record.app_id.value);
  }

  handleDateRange(configDate) {
    if (configDate === 'today') return DateFormatter.formatDate(new Date());

    if (configDate === 'yesterday') {
      const date = new Date();
      date.setDate(date.getDate() - 1);
      return DateFormatter.formatDate(date);
    }

    const daysAgoMatch = configDate.match(/^(\d+)daysAgo$/);
    if (!daysAgoMatch) return DateFormatter.formatDate(new Date(configDate));

    const numberOfDays = parseInt(daysAgoMatch[1], 10);
    const date = new Date();
    date.setDate(date.getDate() - numberOfDays);
    return DateFormatter.formatDate(date);
  }

  async updateRecords(totalsPerAppId, existingApps) {
    const startDate = CONFIG.dateRange.startDate || DEFAULT_CONFIG.dateRange.startDate;
    const endDate = CONFIG.dateRange.endDate || DEFAULT_CONFIG.dateRange.endDate;
    const formattedStartDate = this.handleDateRange(startDate);
    const formattedEndDate = this.handleDateRange(endDate);

    const recordsToUpdate = Array.from(totalsPerAppId, ([appId, data]) => {
      if (existingApps.includes(appId) === false) return null;
      return {
        updateKey: {
          field: 'app_id',
          value: appId.toString(),
        },
        record: {
          [CONFIG.kintone.fields.ga_screen_page_views || DEFAULT_CONFIG.kintone.fields.ga_screen_page_views]: {
            value: data.screenPageViews,
          },
          [CONFIG.kintone.fields.ga_total_users || DEFAULT_CONFIG.kintone.fields.ga_total_users]: {
            value: data.totalUsers,
          },
          [CONFIG.kintone.fields.ga_start_date || DEFAULT_CONFIG.kintone.fields.ga_start_date]: {
            value: formattedStartDate,
          },
          [CONFIG.kintone.fields.ga_end_date || DEFAULT_CONFIG.kintone.fields.ga_end_date]: {
            value: formattedEndDate,
          },
        },
      };
    }).filter((record) => record !== null);

    if (recordsToUpdate.length === 0) {
      console.log('No records to update.');
      return;
    }

    try {
      await this.client.record.updateAllRecords({
        app: CONFIG.kintone.appId,
        records: recordsToUpdate,
      });

      console.log(
        `The analysis results from GA have been successfully updated to ${CONFIG.kintone.baseUrl}/k/${CONFIG.kintone.appId}`
      );
    } catch (error) {
      throw new CustomError(`Error updating data to kintone: ${error.message}`);
    }
  }
}

export class ConfigValidator {
  static validateConfig() {
    const {kintone, ga4} = CONFIG;
    const {baseUrl, appId, apiToken} = kintone;
    const {propertyId} = ga4;

    const baseUrlValidation = this.validateBaseUrl(baseUrl);
    const appIdValidation = this.validateAppId(appId);
    const apiTokenValidation = this.validateApiToken(apiToken);
    const propertyIdValidation = this.validatePropertyId(propertyId);
    const keyFilePathValidation = this.validateKeyFilePath();

    if (baseUrlValidation.isValid === false) return {isValid: false, message: baseUrlValidation.message};
    if (appIdValidation.isValid === false) return {isValid: false, message: appIdValidation.message};
    if (apiTokenValidation.isValid === false) return {isValid: false, message: apiTokenValidation.message};
    if (propertyIdValidation.isValid === false) return {isValid: false, message: propertyIdValidation.message};
    if (keyFilePathValidation.isValid === false) return {isValid: false, message: keyFilePathValidation.message};

    return {isValid: true, message: 'Config is valid.'};
  }

  static validateBaseUrl(url) {
    if (!url) return {isValid: false, message: 'Base URL is required.'};
    return {isValid: true, message: 'Base URL is valid.'};
  }

  static validateAppId(id) {
    if (!id) return {isValid: false, message: 'App ID is required.'};
    if (isNaN(id)) return {isValid: false, message: 'App ID must be a number.'};
    return {isValid: true, message: 'App ID is valid.'};
  }

  static validateApiToken(token) {
    if (!token) return {isValid: false, message: 'API Token is required.'};
    return {isValid: true, message: 'API Token is valid.'};
  }

  static validatePropertyId(id) {
    if (!id) return {isValid: false, message: 'Property ID is required.'};
    if (isNaN(id)) return {isValid: false, message: 'Property ID must be a number.'};
    return {isValid: true, message: 'Property ID is valid.'};
  }

  static validateKeyFilePath() {
    const filePath = CONFIG.ga4.keyFilePath || DEFAULT_CONFIG.ga4.keyFilePath;
    if (fs.existsSync(filePath) === false) return {isValid: false, message: 'Key file path is invalid.'};
    return {isValid: true, message: 'Key file path is valid.'};
  }

  static validateFormFields(formFields, configs) {
    const {kintone: {fields}} = configs;

    const gaScreenPageViews = fields.ga_screen_page_views || DEFAULT_CONFIG.kintone.fields.ga_screen_page_views;
    const gaTotalUsers = fields.ga_total_users || DEFAULT_CONFIG.kintone.fields.ga_total_users;
    const gaStartDate = fields.ga_start_date || DEFAULT_CONFIG.kintone.fields.ga_start_date;
    const gaEndDate = fields.ga_end_date || DEFAULT_CONFIG.kintone.fields.ga_end_date;

    if (!(gaScreenPageViews in formFields)) return {isValid: false, message: `${gaScreenPageViews} field code is invalid.`};
    if (!(gaTotalUsers in formFields)) return {isValid: false, message: `${gaTotalUsers} field code is invalid.`};
    if (!(gaStartDate in formFields)) return {isValid: false, message: `${gaStartDate} field code is invalid.`};
    if (!(gaEndDate in formFields)) return {isValid: false, message: `${gaEndDate} field code is invalid.`};

    return {isValid: true, message: 'Form fields are valid.'};
  }
}
utils.jsのプログラムのポイント解説

次の箇所で、GoogleアナリティクスData APIを使用しています。
サービスアカウントキー(g4-key.json)を使って認証し、GA4のレポートに接続しています。

31
    this.client = new BetaAnalyticsDataClient({keyFile: CONFIG.ga4.keyFilePath || DEFAULT_CONFIG.ga4.keyFilePath});

また、次の箇所でGA4に接続後、指定したプロパティから分析データを取得しています。

36
37
38
39
40
41
42
43
44
45
46
      const [response] = await this.client.runReport({
        property: `properties/${CONFIG.ga4.propertyId}`,
        dateRanges: [
          {
            startDate: CONFIG.dateRange.startDate || DEFAULT_CONFIG.dateRange.startDate,
            endDate: CONFIG.dateRange.endDate || DEFAULT_CONFIG.dateRange.endDate,
          },
        ],
        dimensions: [{name: 'pagePath'}],
        metrics: [{name: 'screenPageViews'}, {name: 'totalUsers'}],
      });
config.jsの作成

GA4とkintoneの接続情報やフィールドコード、日付範囲などを定義する設定ファイルです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * ga integration sample program
 * Copyright (c) 2025 Cybozu
 *
 * Licensed under the MIT License
 * <https://opensource.org/license/mit/>
 */
export const CONFIG = {
  kintone: {
    baseUrl: '',
    appId: '',
    apiToken: '',
    fields: {
      ga_start_date: '',
      ga_end_date: '',
      ga_screen_page_views: '',
      ga_total_users: '',
    },
  },
  ga4: {
    propertyId: '',
    keyFilePath: '',
  },
  dateRange: {
    startDate: '',
    endDate: '',
  },
};

export const DEFAULT_CONFIG = {
  kintone: {
    fields: {
      ga_start_date: 'ga_start_date',
      ga_end_date: 'ga_end_date',
      ga_screen_page_views: 'ga_screen_page_views',
      ga_total_users: 'ga_total_users',
    },
  },
  ga4: {
    keyFilePath: './g4-key.json',
  },
  dateRange: {
    startDate: '30daysAgo',
    endDate: 'today',
  },
};

config.jsの設定

caution
警告

認証情報は「config.js」にハードコーディングしています。
次のページを参考に、実行する環境のセキュリティには十分注意してください。
kintoneセキュアコーディングガイドライン | 認証情報や認可情報を適切に取り扱う

次の表を参考に「config.js」を修正します。

項目 設定内容
baseUrl kintoneのドメイン名を設定します。
例:https://sample.cybozu.com
appId 「アプリ分析結果」アプリのアプリIDを設定します。
apiToken 「アプリ分析結果」アプリのAPIトークンを設定します。
APIトークンに「レコード閲覧」と「レコード編集」の権限を付与します。
ga_start_date GA分析開始日フィールドのフィールドコードを設定します。
デフォルト値はga_start_dateです。
ga_end_date GA分析終了日フィールドのフィールドコードを設定します。
デフォルト値はga_end_dateです。
ga_screen_page_views 合計ページビュー数フィールドのフィールドコードを設定します。
デフォルト値はga_screen_page_viewsです。
ga_total_users 合計ユニークユーザー数フィールドのフィールドコードを設定します。
デフォルト値はga_total_usersです。
propertyId GAのプロパティIDを設定します。
GAの管理画面から「プロパティ設定」>「プロパティの詳細」で確認できます。
keyFilePath ダウンロードした認証情報ファイルへの絶対パスを設定します。
デフォルト値は./g4-key.jsonです。
startDate 分析レポートの開始日を設定します。
デフォルト値は30daysAgoです。
日付の設定値の詳細は DateRange (External link) を参照してください。
endDate 分析レポートの終了日設定します。
デフォルト値はtodayです。
日付の設定値の詳細は DateRange (External link) を参照してください。

以上で、Node.jsスクリプトの作成は完了です。

動作確認

それでは、動作確認をしてみましょう。
ターミナルで「sample-program」ディレクトリに移動し、次のコマンドを実行します。

1
node index.js

成功すると、ターミナルに次のメッセージが表示されます。

1
2
The analysis results from GA have been successfully fetched.
The analysis results from GA have been successfully updated to https://XXXX

取得したGAのデータは 完成イメージ のように「アプリ分析結果」アプリに表示されます。

information

アクセスのない(GAでの分析がされていない)アプリの場合、GA関連のすべてのフィールドは空になります。

おわりに

本記事では、ワイドコースのアプリ分析ツールとGAを連携し、アクセス数や利用ユーザー数をkintoneアプリに反映する方法を紹介しました。
GAと連携することで、より詳細な利用状況の把握やデータに基づいた運用改善が可能です。
自社の運用に合わせて分析項目や期間を調整し、アプリ分析ツールをより効果的に活用してください。

information

このTipsは、2025年9月版kintoneで動作を確認しています。