Notion × kintone連携!JavaScriptカスタマイズでデータ同期

目次

はじめに

今回は、kintoneとNotionをAPIで連携する方法を紹介します。
kintoneは柔軟性とカスタマイズ性が高く、他のサービスとの連携も容易です。
この記事では、kintoneのJavaScriptカスタマイズ機能を活用して、Notionからデータを取得する方法を解説します。

Notionの特徴と、連携のメリット

Notion (External link) は、ノートテイキングやタスク管理、データベース管理など、多様な機能をもつワークスペースです。
ビジネスの現場で必要とされるさまざまなアプリケーションを簡単に作成、管理できるクラウドサービスのkintoneと、 Notionを連携することで、Notionに蓄積された情報をkintoneのアプリでも活用できます。
これにより、業務の効率化や情報共有のスムーズ化が期待できます。

kintoneとNotionの連携方法

kintoneのJavaScriptカスタマイズ機能を使うと、kintoneのアプリケーションに独自の機能を追加できます。
kintoneのカスタマイズとは
たとえば、特定の条件でフィールドの表示を変更したり、外部サービスとのデータ連携ができます。
また、Notionも、外部と連携するためのインターフェースとして、Notion APIを用意しています。
そこで、今回はJavaScriptカスタマイズを利用し、kintone側からNotion APIへリクエストすることによって、NotionのAPIと連携してみます。
今回のカスタマイズ例では、次の流れで行ってみましょう。

  1. Notionにデータベースを用意する。
  2. Notionに新しいコネクトを作成する。
  3. 作成したコネクトからデータベースへアクセスができるようにする。
  4. kintoneにアプリを作成する。
  5. kintoneにJavaScriptカスタマイズを適用する。
    今回は例として商品管理アプリを作成し、Notion側にある商品リストをkintone側へ連携するようにしてみます。

1. Notionにデータベースを用意する

Notion側にデータベースを作成しましょう。
データベースの概要、作り方についてはNotionのヘルプページ データベースの基本 (External link) を確認してください。

テーブルのプロパティは次のように設定してください。

プロパティ名 プロパティの種類 備考
商品名 タイトル
販売ステータス 選択 販売中 販売一時停止 販売終了を項目に設定
金額 数値 数値の形式にを指定
詳細 テキスト

2. Notionに新しいコネクトを作成する

kintoneからNotionのデータにアクセスするため、Notion APIを利用します。
そのための設定が必要ですので、 コネクト設定画面 (External link) を開き、新しいコネクトを作成してください。
基本情報を設定し、コンテンツの読み取り権限を付与してください。

最後にJavaScriptカスタマイズへ利用するためアクセストークンをコピーして控えておいてください。

コネクトの詳細については、ヘルプページ コネクト (External link) を参照ください。

3. 作成したコネクトからデータベースへアクセスができるようにする

コネクトを作成するだけでは、最初はワークスペース内のどのコンテンツにもアクセスできません。
そのため、今回利用するデータベース側で接続するコネクトを設定する必要があります。

1. Notionにデータベースを用意する で作成したデータベースのページ上で下記を行ってください。

  1. 右上の三点リーダをクリック
  2. 「接続」をクリック
  3. 作成したコネクトをクリック
  4. ダイアログが表示されるので「ページに追加」をクリック

これで作成したコネクトからデータベースにアクセスできます。

4. kintoneにアプリを作成する

今回は下記フィールドをもつアプリを用意します。
わかりやすくするためにここではフィールド名とフィールドコードは同一とします。

フィールド名/フィールドコード フィールドの種類 備考
商品名 文字列(1行)
販売ステータス ドロップダウン Notion側に合わせて販売中 販売一時停止 販売終了を項目に設定
金額 数値 桁区切りや単位記号の設定は任意
詳細 文字列(複数行)
notion_id 文字列(1行) Notion側との紐づけのために利用する。
値の重複を禁止するをチェック

5. kintoneにJavaScriptカスタマイズを適用する

information

JavaScriptカスタマイズの詳細についてはヘルプページ JavaScriptやCSSでアプリをカスタマイズする (External link) を参照してください。

アプリ設定の[JavaScript / CSSでカスタマイズ]に下記URLとファイルを追加します。

  1. https://unpkg.com/kintone-ui-component@1.24.0/umd/kuc.min.js
    • 今回はボタンの表示にkintone UI Componentを利用しますので、そのためのURLを追加します。 kintone UI Componentについての詳細は kintone UI Component v1 を参照してください。
  2. Notion APIの下記コードを保存し、JavaScriptカスタマイズとして適用してください。
    下記はご自身のNotionに合わせて書き換えてください。
    • [YOUR_DATABASE_ID]: 今回作成したNotionのデータベースID。
      • たとえばブラウザーでデータベースにアクセスした時のURLが
        https://www.notion.so/your_domain/f2d589bf26604ebe8cdccc3c6c9d0d6d?v=180a664ab56c41f4bf9049cc5c438284なら、 f2d589bf26604ebe8cdccc3c6c9d0d6dがデータベースIDにあたります。
    • [YOUR_ACCESS_TOKEN]: 先ほど取得したアクセストークンです。
caution
警告

アクセストークン等の秘密情報は、絶対に公開しないでください。
秘密情報が漏洩するとAPIを自由に実行できてしまうため、kintoneのJavaScriptの開発においても慎重に扱ってください。

cybozu develper networkでは、認証情報の秘匿にプラグインを利用する方法を推奨しています。詳しくは以下の記事を確認してください。

  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
/*
 * Notion のデータを kintone に同期するサンプルプログラム
 * Copyright (c) 2026 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */
(() => {
  'use strict';

  // Notion APIの設定
  const DATABASE_ID = '[YOUR_DATABASE_ID]';
  const NOTION_API_HEADERS = {
    Authorization: 'Bearer [YOUR_ACCESS_TOKEN]',
    'Notion-Version': '2026-03-11',
    'Content-Type': 'application/json'
  };

  // kintone ui componentのバージョン指定
  const Kuc = Kucs['1.24.0'];

  // 同期ボタンの設定
  const syncButton = new Kuc.Button({
    text: 'Notionデータ同期',
    type: 'submit'
  });

  // 同期が始まったときにボタンを非活性化するための関数
  const disableSyncButton = () => {
    syncButton.text = 'loading...';
    syncButton.disabled = true;
  };

  // データベースから「データソースID」を取得する関数
  const getDataSourceId = async () => {
    const url = `https://api.notion.com/v1/databases/${DATABASE_ID}`;
    const response = await kintone.proxy(url, 'GET', NOTION_API_HEADERS, {});
    const data = JSON.parse(response[0]);

    // 最初のデータソースIDを返す
    return data.data_sources[0].id;
  };

  // Notionのデータを取得する関数
  const fetchNotionData = async () => {
    // データソースIDを取得
    const dataSourceId = await getDataSourceId();
    // Notionのデータを取得
    const NOTION_DATA_SOURCE_URL = `https://api.notion.com/v1/data_sources/${dataSourceId}/query`;
    const response = await kintone.proxy(NOTION_DATA_SOURCE_URL, 'POST', NOTION_API_HEADERS, {});
    const notionData = JSON.parse(response[0]);
    return notionData;
  };

  // Notionとkintoneを同期させるための関数
  const syncNotionToKintone = async () => {
    // Notionのデータを取得し、なければ終了する
    const notionData = await fetchNotionData();
    if (notionData.results.length === 0) {
      alert('Notionのデータが空です');
      return;
    }
    // 取得したNotionのデータとkintoneのデータを元にPUTのupsertモードでデータの作成と更新を行う。
    // 更新のためのパラメータの定義
    const params = {
      app: kintone.app.getId(),
      upsert: true,
      records: notionData.results.map(targetNotionData => {
        return {
          updateKey: {
            field: 'notion_id',
            value: targetNotionData.id
          },
          record: {
            商品名: {
              value: targetNotionData.properties.商品名.title.map(t => t.plain_text).join('')
            },
            販売ステータス: {
              value: targetNotionData.properties.販売ステータス.select.name
            },
            金額: {
              value: targetNotionData.properties.金額.number
            },
            詳細: {
              value: targetNotionData.properties.詳細.rich_text.map(t => t.plain_text).join('')
            }
          }
        };
      })
    };

    // kintoneにPUTリクエスト(upsertモード)の送信
    await kintone.api(kintone.api.url('/k/v1/records.json', true), 'PUT', params);
  };

  // レコード一覧画面を表示した後のイベント
  kintone.events.on('app.record.index.show', (event) => {

    // 同期ボタンを設置
    const headerSpace = kintone.app.getHeaderMenuSpaceElement();
    headerSpace.appendChild(syncButton);

    // 同期ボタンクリック時の処理
    syncButton.addEventListener('click', async () => {
      disableSyncButton();
      await syncNotionToKintone();
      location.reload();
    });

    return event;
  });

})();

6. 動作確認

画像のように同期ボタンが表示されます。
クリックすることで、Notionとkintoneのデータ同期が開始されます。

「loading...」が続き、処理が進まないようであれば、NotionのデータベースIDやアクセストークンが間違っている可能性があります。
コンソールを開き、確認してください。

コードの解説

上記コードにおけるポイントをいくつか解説します。

kintone UI Componentの利用

今回のサンプルでは同期ボタンにkintone UI Componentを利用しています。

19
20
21
22
23
24
25
26
27
28
29
30
31
32
  // kintone ui componentのバージョン指定
  const Kuc = Kucs['1.24.0'];

  // 同期ボタンの設定
  const syncButton = new Kuc.Button({
    text: 'Notionデータ同期',
    type: 'submit'
  });

  // 同期が始まったときにボタンを非活性化するための関数
  const disableSyncButton = () => {
    syncButton.text = 'loading...';
    syncButton.disabled = true;
  };
 99
100
101
102
103
104
105
106
107
108
    // 同期ボタンを設置
    const headerSpace = kintone.app.getHeaderMenuSpaceElement();
    headerSpace.appendChild(syncButton);

    // 同期ボタンクリック時の処理
    syncButton.addEventListener('click', async () => {
      disableSyncButton();
      await syncNotionToKintone();
      location.reload();
    });

kintone UI Componentの詳細については、 kintone UI Component v1 を確認してください。
この記事では説明を割愛します。

Notion APIとの通信

Notion APIはkintone外部のAPIなので、通信するためにkintone.proxy()を利用しています。
kintone.proxyの使い方や詳細については 外部のAPIを実行する を参照してください。

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  // データベースから「データソースID」を取得する関数
  const getDataSourceId = async () => {
    const url = `https://api.notion.com/v1/databases/${DATABASE_ID}`;
    const response = await kintone.proxy(url, 'GET', NOTION_API_HEADERS, {});
    const data = JSON.parse(response[0]);

    // 最初のデータソースIDを返す
    return data.data_sources[0].id;
  };

  // Notionのデータを取得する関数
  const fetchNotionData = async () => {
    // データソースIDを取得
    const dataSourceId = await getDataSourceId();
    // Notionのデータを取得
    const NOTION_DATA_SOURCE_URL = `https://api.notion.com/v1/data_sources/${dataSourceId}/query`;
    const response = await kintone.proxy(NOTION_DATA_SOURCE_URL, 'POST', NOTION_API_HEADERS, {});
    const notionData = JSON.parse(response[0]);
    return notionData;
  };

また、Notion APIからは、どのようなレスポンスが返ってくるかなどはNotion APIのリファレンス Query a data source (External link) を参照してください。

Notion側との同期

syncNotionToKintone()という関数を用意し、その中でUPSERT処理をします。
UPSERTとは、指定のレコードがなかったら登録、あったらレコードの内容を更新する処理のことを指します。
ここでは 複数のレコードを更新する のupsertモードを利用しています。

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
  // Notionとkintoneを同期させるための関数
  const syncNotionToKintone = async () => {
    // Notionのデータを取得し、なければ終了する
    const notionData = await fetchNotionData();
    if (notionData.results.length === 0) {
      alert('Notionのデータが空です');
      return;
    }
    // 取得したNotionのデータとkintoneのデータを元にPUTのupsertモードでデータの作成と更新を行う。
    // 更新のためのパラメータの定義
    const params = {
      app: kintone.app.getId(),
      upsert: true,
      records: notionData.results.map(targetNotionData => {
        return {
          updateKey: {
            field: 'notion_id',
            value: targetNotionData.id
          },
          record: {
            商品名: {
              value: targetNotionData.properties.商品名.title.map(t => t.plain_text).join('')
            },
            販売ステータス: {
              value: targetNotionData.properties.販売ステータス.select.name
            },
            金額: {
              value: targetNotionData.properties.金額.number
            },
            詳細: {
              value: targetNotionData.properties.詳細.rich_text.map(t => t.plain_text).join('')
            }
          }
        };
      })
    };

    // kintoneにPUTリクエスト(upsertモード)の送信
    await kintone.api(kintone.api.url('/k/v1/records.json', true), 'PUT', params);
  };

kintoneイベントハンドラーの定義

今回はレコード一覧画面に同期ボタンを表示していますので、 レコード一覧画面を表示した後のイベント を利用します。

 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
  // レコード一覧画面を表示した後のイベント
  kintone.events.on('app.record.index.show', (event) => {

    // 同期ボタンを設置
    const headerSpace = kintone.app.getHeaderMenuSpaceElement();
    headerSpace.appendChild(syncButton);

    // 同期ボタンクリック時の処理
    syncButton.addEventListener('click', async () => {
      disableSyncButton();
      await syncNotionToKintone();
      location.reload();
    });

    return event;
  });

注意事項

  • 提示しているコードはあくまで連携のサンプルなためNotion側、kintone側ともに100件までのレコード数を想定しており、それ以上のレコード数は想定しておりません。
    • 今回利用しているNotion APIも一度に取得できるのは執筆時点で100件までとなっています。

まとめ

kintoneとNotionの連携は、ビジネスの効率化に大きく貢献します。
kintoneのJavaScriptカスタマイズ機能を活用することで、さまざまな外部サービスとの連携が可能になり、業務の幅が広がります。
この記事を参考に、ぜひkintoneとNotionの連携に挑戦してみてください!

information

このTipsは、2026年5月版kintoneとNotionで動作を確認しています。