kintoneとGoogleスプレッドシートの連携

公開 書いた人 大林 諒

kintoneのデータをGoogleスプレッドシートで見たい、シートに溜まった申込をkintoneに入れたい、という相談は多いです。kintoneの標準機能には、スプレッドシートと自動で同期する設定はありません。つなぐ方法は、CSVを手で受け渡す、Apps ScriptからREST APIを呼ぶ、連携サービスを入れる、iPaaSを使う、の4つです。この記事では、どちらを正にするかを先に決めたうえで、CSVの手順、Apps Scriptで取得と登録をするコード、定期実行、制限まで通して書きます。アプリ管理権限があり、kintoneのスタンダードコース以上を契約していることを前提にしています。

この記事の内容
  1. なぜスプレッドシートとつなぐのか
  2. 先に決めること
  3. 設計表
  4. 手動でつなぐ(CSVの書き出しと取り込み)
  5. Apps Scriptでkintoneからシートへ書く
  6. シートからkintoneへ登録する
  7. 定期実行する
  8. 連携サービスとiPaaSを使う
  9. 応用
  10. 制限
  11. できないことと、その代わり
  12. よく詰まるところ
  13. 次にやること

なぜスプレッドシートとつなぐのか

つなぎたい理由は、だいたい次の3つです。理由によって向きと方法が変わります。

理由向きよくある例
集計kintone → シート案件の金額を担当者別、月別に好きな形で集計する。ピボットテーブルや関数で加工する
共有kintone → シートkintoneのアカウントを持たない社外の人や役員に、決まった列だけを見せる
外部とのやり取りシート → kintone取引先や別部署がシートに書いた申込、フォームの回答をkintoneに取り込む

集計と共有はkintoneからシートへ、外部とのやり取りはシートからkintoneへの一方通行で足ります。両方向を自動でつなぐ必要がある場面は、実際にはほとんどありません。

先に決めること

どちらを正にするか

一番大事なのはここです。同じデータが2か所にあるとき、食い違ったらどちらを信じるかを決めておきます。正にするのはkintoneです。

シートは誰でもセルを書き換えられ、並べ替えや削除の記録も残りにくい道具です。kintoneはアクセス権で編集できる人を絞れて、レコードごとに変更履歴が残ります。シートを正にすると、誰がいつ数字を変えたのかが追えなくなります。

決めるルールは次の3つです。

  • kintoneから書き出したシートは、見るための写しにする。シートで値を直しても、kintoneには戻さない
  • 値を直すときはkintoneで直し、次の書き出しでシートに反映させる
  • シートからkintoneに入れる場合、シートは受付の入口にすぎない。kintoneに入った時点で、正はkintoneに移る

写しのシートは保護をかけて編集できる人を絞り、シート名に「kintoneの写し」と入れておきます。

向きは片方向にする

両方で編集でき、どちらで直しても相手に反映される作りは避けます。同時に直したときにどちらを残すか、消したら相手も消すのか、という判断を全部コードで書くことになり、壊れたときに直せる人がいなくなります。向きは1本のつなぎごとに片方向にします。

方法を選ぶ

方法向いている場面手間費用
手動(CSVの書き出しと取り込み)月に数回、決まった人が更新する毎回の手作業追加なし
Apps Script+REST API毎日や毎時の自動更新。社内にコードを読める人がいる最初の作り込み追加なし
連携サービス(プラグインや外部の連携製品)コードを持ちたくない。サポートが欲しい設定のみ製品ごとの月額
iPaaS(ZapierやPower Automateなど)Googleとkintone以外のサービスもまとめてつなぐ画面で組むサービスごとの月額

迷ったら、まずCSVで1か月回します。手作業が負担になったころには、何をどの頻度で動かしたいかがはっきりしているので、同じことをApps Scriptで自動にします。

コースを確かめる

APIトークン、Webhook、Power Automateとの連携は、ライトコースでは使えません。kintoneの料金ページでも、外部サービス連携やプラグインなどの拡張機能はライトコースが非対応、スタンダードコースとワイドコースが対応と書かれています。料金は1ユーザーあたり月額でライトコースが1,000円、スタンダードコースが1,800円(どちらも税抜、最小10ユーザー)です。ライトコースのままなら、この記事の方法のうち使えるのは手動のCSVだけです。

設計表

この記事では2つのつなぎを例にします。1つは「案件管理」アプリの案件を毎朝シートに書き出して集計するつなぎ、もう1つはシートに溜まる問い合わせを「問い合わせ管理」アプリに登録するつなぎです。

案件管理(kintone → シート)

フィールド名種類設定
案件名文字列(1行)必須
顧客名文字列(1行)顧客マスタがあるならルックアップ
担当者ユーザー選択必須
金額数値桁区切りの表示は任意。書き出しには影響しない
受注予定日日付月別の集計に使う
進捗ドロップダウン見込み/提案中/受注/失注
更新日時更新日時差分だけ取るときの条件に使う

フィールドコードはスクリプトの中で使います。フィールド名と同じ文字にそろえておくと、コードを読むときに迷いません。

問い合わせ管理(シート → kintone)

フィールド名種類設定
受付ID文字列(1行)必須。「値の重複を禁止する」をオン。二重登録を防ぐキー
受信日時日時シートの受信日時を入れる
氏名文字列(1行)必須
メールアドレス文字列(1行)返信に使う
問い合わせ内容文字列(複数行)
対応状況ドロップダウン未対応/対応中/完了。初期値は未対応

受付シートの列

列中身誰が書くか
受信日時問い合わせを受けた日時入力者、またはフォーム
氏名、メールアドレス、問い合わせ内容本文入力者、またはフォーム
受付ID1行ごとに一意な番号スクリプト(空なら振る)
kintone登録登録した日時スクリプト(入っている行は送らない)

受付IDとkintone登録の2列は、人が書かない列です。列の見出しに色を付けるか、保護をかけて、入力者が触らないようにします。

手動でつなぐ(CSVの書き出しと取り込み)

kintoneから書き出す

書き出されるのは、レコードの一覧画面に出ているレコードです。先に一覧や絞り込みで、必要なレコードだけが出ている状態にします。

  1. 案件管理のレコードの一覧を開き、書き出したいレコードが出ている一覧を選びます。
  2. 右上の「オプション」アイコンをクリックします。
  3. 「ファイルに書き出す」をクリックします。
  4. 「先頭行を項目名にする」にチェックが入っていることを確かめます。
  5. 「文字コード」を選びます。スプレッドシートで開くならUTF-8かBOM付きUTF-8にします。
  6. 「区切り文字」で「カンマ」を選びます。
  7. 書き出すフィールドをドラッグして並べます。全部なら「すべて追加」をクリックします。
  8. 「書き出す」をクリックします。
  9. 「出力されたファイル」の画面が開くので、処理が終わったらファイル名をクリックしてダウンロードします。

「ファイルに書き出す」が出てこないときは、アプリのアクセス権で「ファイル書き出し」の権限がありません。初期状態ではアプリの作成者にしかこの権限がないので、書き出す担当者に付けておきます。

「ファイルに書き出す」の画面。文字コード、区切り文字、書き出すフィールドの3か所
「ファイルに書き出す」の画面。文字コード、区切り文字、書き出すフィールドの3か所

「出力オプション」には、ユーザーや組織を表示名で出す「ユーザー、組織、グループを表示名で出力する」があります。シートで人に見せるならチェックを入れます。ただし表示名で書き出したファイルは、ユーザー選択の値としてkintoneに読み込み直せません。読み込みに使うファイルは、ログイン名のまま書き出します。

文字コードは、BOM付きUTF-8がExcel向け、UTF-8が異体字や記号、絵文字を含むデータ向けと案内されています。スプレッドシートならUTF-8系を選んでおけば困りません。

書き出したファイルの仕様

シートに取り込んでから「列が多い」「行が増えた」と慌てないように、書き出しの仕様を押さえておきます。

項目書き出され方
対象のレコードレコードの一覧に出ているレコード。閲覧権限のないレコードとフィールドは出ない
数値、計算桁区切りと単位記号は付かない
チェックボックス、複数選択選択肢ごとに1列。選ばれていれば「1」
日付、日時月と日は0埋め。並びは書き出した人の表示言語で変わる(日本語なら年/月/日)
テーブル1レコードが複数行になる。1列目に「*」がある行がレコードの始まり
ラベル、添付ファイル、関連レコード一覧、変更履歴書き出せない
ファイルの大きさ100MBを超えると書き出しに失敗する
保存期間書き出しを始めてから3日間ダウンロードできる

テーブルのあるアプリは、テーブル以外の値が行ごとに繰り返されるので、そのままシートで合計すると金額が行数ぶん重なります。テーブルの明細を集計したいときは、テーブルの列だけを使い、親の値の合計は「*」のある行だけで取ります。

スプレッドシートに取り込む

  1. 集計用のスプレッドシートを開きます。
  2. 「ファイル」から「インポート」をクリックします。
  3. 書き出したCSVを選びます。
  4. 読み込みオプションで「現在のシートを置換する」を選びます。
  5. 区切り文字はカンマにします。
  6. 「インポート」をクリックします。

「現在のシートに行を追加する」を選ぶと、前回の行の下に今回の全件が足され、同じ案件が2回数えられます。集計の式やピボットテーブルは、取り込み用のシートとは別のシートに置き、取り込み用のシートを参照させます。置換しても集計の側が壊れません。

【画面:スプレッドシートのインポートの画面。読み込みオプションで「現在のシートを置換する」を選んだ状態】

シートからkintoneへ戻す

シートの行をkintoneに入れるときは、シートをCSVでダウンロードして、kintoneで読み込みます。

  1. スプレッドシートで、読み込みたい行だけのシートを開きます。
  2. ファイルのメニューからCSV形式でダウンロードします。
  3. 問い合わせ管理のレコードの一覧で「オプション」アイコンをクリックし、「ファイルから読み込む」を選びます。
  4. 「ファイルを選択」でダウンロードしたCSVを指定します。
  5. 「先頭行をファイルの列名として扱う」を確かめます。
  6. 「読み込むファイルのプレビュー」で文字化けと列ずれがないか見ます。化けていたら「文字コード」を変えます。
  7. 「アプリへの反映方法」で「レコードの更新と追加」を選びます。
  8. 「更新キー」に受付ID、「対応するファイルの列」に受付IDの列を選びます。
  9. 各フィールドに読み込む列を対応付け、読み込まないフィールドは「(指定しない)」にします。
  10. 「読み込む」をクリックします。

「レコードの更新と追加」にして受付IDを更新キーにしておくと、同じファイルを2回読み込んでも、既にある受付IDは上書きになり、レコードは増えません。更新キーにレコード番号以外を使うには、そのフィールドで「値の重複を禁止する」がオンになっている必要があります。CSVは1ファイル100MB、10万行まで、Excel形式は1MB、1,000行までです。

エラー行の扱いは「読み込みを継続する(エラー行のみスキップします)」と「読み込みを中止する(エラー行以降の行は読み込みません)」から選びます。どちらでもエラーより前の行は読み込まれるので、取り消しにはなりません。読み込む前に、いまのレコードを書き出してバックアップを取っておきます。読み込みには、アプリのアクセス権で「ファイル読み込み」の権限が要ります。

「ファイルから読み込む」の画面。アプリへの反映方法と更新キーを設定した状態
「ファイルから読み込む」の画面。アプリへの反映方法と更新キーを設定した状態

Apps Scriptでkintoneからシートへ書く

ここからは自動にします。Apps Scriptはスプレッドシートに付いているスクリプトの仕組みで、サーバーを用意せずにREST APIを呼べます。

APIトークンを作る

  1. 案件管理のレコードの一覧で、右上の歯車の「アプリを設定」をクリックします。
  2. 「設定」タブを開きます。
  3. 「カスタマイズ/サービス連携」の「APIトークン」をクリックします。
  4. 「生成する」をクリックします。
  5. 「アクセス権」で、レコードの閲覧だけにチェックを入れます。
  6. 「メモ」に「スプレッドシート連携(案件の書き出し)」のように用途を書きます。
  7. 「保存」をクリックします。
  8. 「アプリを更新」をクリックし、確認の画面でもう一度「アプリを更新」をクリックします。

最後の「アプリを更新」を忘れると、トークンは効きません。トークンは1アプリ20個まで作れます。用途ごとに分けておくと、1つのつなぎを止めたいときにそのトークンだけ消せます。

トークンの権限は、アプリやレコード、フィールドのアクセス権より優先されます。閲覧だけで足りるつなぎに、編集や削除まで付けたトークンを使い回さないようにします。

APIトークンの画面。生成したトークンのアクセス権でレコード閲覧だけにチェックが入った状態
APIトークンの画面。生成したトークンのアクセス権でレコード閲覧だけにチェックが入った状態

トークンをスクリプトに置く

  1. 集計用のスプレッドシートを開きます。
  2. 「拡張機能」から「Apps Script」を選びます。
  3. 左の「プロジェクト設定」を開きます。
  4. 「スクリプト プロパティ」に、プロパティ名を KINTONE_TOKEN_ANKEN、値を生成したトークンにして追加し、保存します。

コードに直接書くと、スクリプトのコピーや画面共有で一緒に出回ります。コードからは名前で読みます。

【画面:Apps Scriptのプロジェクト設定。スクリプト プロパティにトークンを追加した状態】

取得して書き込むコード

サブドメインとアプリIDはダミーの値です。自分の環境の値に置き換えます。アプリIDは、アプリを開いたときのURLの /k/ の後ろの数字です。

const SUBDOMAIN = 'example';   // https://example.cybozu.com の example
const ANKEN_APP_ID = 123;

function fetchAllRecords_(appId, token, fields, condition) {
  const records = [];
  let lastId = 0;
  while (true) {
    const q = (condition ? '(' + condition + ') and ' : '') +
              '$id > ' + lastId + ' order by $id asc limit 500';
    let url = 'https://' + SUBDOMAIN + '.cybozu.com/k/v1/records.json' +
              '?app=' + appId + '&query=' + encodeURIComponent(q);
    fields.forEach(function (f, i) {
      url += '&' + encodeURIComponent('fields[' + i + ']') + '=' + encodeURIComponent(f);
    });
    const res = UrlFetchApp.fetch(url, {
      method: 'get',
      headers: { 'X-Cybozu-API-Token': token },
      muteHttpExceptions: true
    });
    if (res.getResponseCode() !== 200) {
      throw new Error('kintoneの取得に失敗: ' + res.getContentText());
    }
    const batch = JSON.parse(res.getContentText()).records;
    batch.forEach(function (r) { records.push(r); });
    if (batch.length < 500) break;
    lastId = Number(batch[batch.length - 1].$id.value);
  }
  return records;
}

function exportAnken() {
  const token = PropertiesService.getScriptProperties().getProperty('KINTONE_TOKEN_ANKEN');
  const fields = ['$id', '案件名', '顧客名', '担当者', '金額', '受注予定日', '進捗', '更新日時'];
  const records = fetchAllRecords_(ANKEN_APP_ID, token, fields, '進捗 not in ("失注")');

  const header = ['レコードID', '案件名', '顧客名', '担当者', '金額', '受注予定日', '進捗', '更新日時'];
  const rows = records.map(function (r) {
    return [
      Number(r.$id.value),
      r['案件名'].value,
      r['顧客名'].value,
      r['担当者'].value.map(function (u) { return u.name; }).join(','),
      r['金額'].value === '' ? '' : Number(r['金額'].value),
      r['受注予定日'].value || '',
      r['進捗'].value,
      new Date(r['更新日時'].value)
    ];
  });

  const sheet = SpreadsheetApp.getActive().getSheetByName('kintoneの写し_案件');
  sheet.clearContents();
  sheet.getRange(1, 1, 1, header.length).setValues([header]);
  if (rows.length > 0) {
    sheet.getRange(2, 1, rows.length, header.length).setValues(rows);
  }
}

書き終えたら exportAnken を選んで実行します。初回は求められる許可を与えます。

【画面:Apps Scriptのエディタ。exportAnkenを選んで実行し、実行ログに完了が出た状態】

コードの読み方

取得は、レコードを一括取得するAPI(GET /k/v1/records.json)を使います。1回で取れるのは500件までで、limit を書かないと100件しか返りません。件数が多いアプリで offset を増やしながら取る書き方をすると、offset の上限が10,000なので1万件を超えたところで取れなくなります。

そこで、レコードID($id)の昇順に並べ、前回取った最後のIDより大きいものを次に取る書き方にしています。cybozu developer networkで「シーク法」として紹介されている取り方で、件数がいくら増えても止まりません。取得した件数が500未満になったら最後のページです。

fields は取るフィールドの指定です。$id は次の取得の起点なので必ず入れます。

返ってくる値は、数値もレコード番号も文字列です。Number() で数に直してから書かないと、シートで文字として扱われ、SUMで合計できません。日時は 2026-10-01T00:30:00Z のような協定世界時の形で返るので、new Date() に通してからシートに書きます。シートの表示はスプレッドシートのタイムゾーンの時刻になります。ユーザー選択はユーザーコード(code)と表示名(name)の組の配列なので、名前だけを取り出してつないでいます。

シートへの書き込みは1行ずつではなく、配列にまとめて setValues で一度に書きます。シートの操作は回数が多いほど遅くなります。

シートからkintoneへ登録する

二重登録を防ぐキー

シートからkintoneへ送るつなぎで一番起きる事故は、同じ行が2回登録されることです。スクリプトが途中で止まり、kintoneには登録したのにシートに「登録済み」と書く前に終わった、というのが典型です。次の実行で同じ行がもう一度送られます。

防ぎ方は2段構えにします。

  • 行ごとに一意な受付IDを持たせ、kintoneの受付IDで「値の重複を禁止する」をオンにする
  • 登録は「追加」ではなく、受付IDをキーにした「更新、なければ追加」で送る

レコードを更新するAPI(PUT /k/v1/records.json)には、updateKey でキーのフィールドを指定し、upsert を true にすると、キーが一致するレコードがあれば更新、なければ追加する動きがあります。同じ行を2回送っても2回目は上書きになるので、レコードは増えません。updateKey に指定できるのは、重複禁止を設定した文字列(1行)か数値だけです。

受付IDに行番号をそのまま使うと、並べ替えや行の挿入で別の問い合わせを指すようになります。最初にスクリプトが振った値をシートに書き込み、以後は変えません。

APIトークンと登録のコード

問い合わせ管理のアプリで、レコード追加とレコード編集にチェックを入れたAPIトークンを作ります。upsert を使うとき、更新の権限に加えて追加の権限も要るためです。スクリプト プロパティに KINTONE_TOKEN_TOIAWASE として置きます。

const TOIAWASE_APP_ID = 124;

function pushInquiries() {
  const token = PropertiesService.getScriptProperties().getProperty('KINTONE_TOKEN_TOIAWASE');
  const sheet = SpreadsheetApp.getActive().getSheetByName('問い合わせ受付');
  const values = sheet.getDataRange().getValues();
  const header = values[0];
  const c = {
    at: header.indexOf('受信日時'),
    name: header.indexOf('氏名'),
    mail: header.indexOf('メールアドレス'),
    body: header.indexOf('問い合わせ内容'),
    key: header.indexOf('受付ID'),
    done: header.indexOf('kintone登録')
  };

  const targets = [];
  for (let i = 1; i < values.length; i++) {
    const row = values[i];
    if (row[c.done] !== '' || row[c.name] === '') continue;
    if (row[c.key] === '') {
      row[c.key] = 'Q' + Utilities.formatDate(new Date(row[c.at]), 'Asia/Tokyo', 'yyyyMMddHHmmss') + '-' + (i + 1);
      sheet.getRange(i + 1, c.key + 1).setValue(row[c.key]);
    }
    targets.push({ rowNo: i + 1, row: row });
  }

  for (let s = 0; s < targets.length; s += 100) {
    const chunk = targets.slice(s, s + 100);
    const body = {
      app: TOIAWASE_APP_ID,
      upsert: true,
      records: chunk.map(function (t) {
        return {
          updateKey: { field: '受付ID', value: String(t.row[c.key]) },
          record: {
            '受付ID': { value: String(t.row[c.key]) },
            '受信日時': { value: Utilities.formatDate(new Date(t.row[c.at]), 'UTC', "yyyy-MM-dd'T'HH:mm:ss'Z'") },
            '氏名': { value: String(t.row[c.name]) },
            'メールアドレス': { value: String(t.row[c.mail]) },
            '問い合わせ内容': { value: String(t.row[c.body]) }
          }
        };
      })
    };
    const res = UrlFetchApp.fetch('https://' + SUBDOMAIN + '.cybozu.com/k/v1/records.json', {
      method: 'put',
      contentType: 'application/json',
      headers: { 'X-Cybozu-API-Token': token },
      payload: JSON.stringify(body),
      muteHttpExceptions: true
    });
    if (res.getResponseCode() !== 200) {
      throw new Error('kintoneの登録に失敗: ' + res.getContentText());
    }
    const now = new Date();
    chunk.forEach(function (t) {
      sheet.getRange(t.rowNo, c.done + 1).setValue(now);
    });
  }
}

登録も更新も、1回のリクエストで送れるのは100件までなので、100件ずつに分けて送っています。1回のリクエストの中で1件でも失敗すると、そのリクエストの100件は全部取り消されます。kintone登録の列に日時を書くのは、レスポンスが成功で返ってきた後だけにしています。失敗したら列は空のまま残り、次の実行でもう一度送られます。受付IDで上書きになるので、送り直しても増えません。record の中にも受付IDを入れているのは、新しく登録されるレコードに受付IDを確実に持たせるためです。受付IDは必須にしているので、ここが空だと登録で止まります。

日時のフィールドには、協定世界時に直した 2026-10-22T01:00:00Z の形で送ります。シートの日時をそのまま文字にして送ると、9時間ずれたり、形式が合わずにエラーになったりします。

対応状況はシートから送りません。送ると、kintoneで「対応中」に変えたあとに送り直したとき、初期値で上書きされます。送るのは受付の時点で決まっている値だけです。

【画面:問い合わせ受付のシート。受付IDとkintone登録の列にスクリプトが値を書いた状態】

問い合わせ管理の一覧。受付IDごとに1件ずつ登録された状態
問い合わせ管理の一覧。受付IDごとに1件ずつ登録された状態

定期実行する

手で実行して動くことを確かめたら、時間で動くトリガーを付けます。

  1. Apps Scriptのエディタで、左の「トリガー」をクリックします。
  2. 右下の「トリガーを追加」をクリックします。
  3. 実行する関数に exportAnken を選びます。
  4. 時間で動く種類を選び、毎日の時刻か、何時間おきかを選びます。
  5. 「保存」をクリックします。

コードで作ることもできます。次の関数を一度だけ実行すると、pushInquiries を6時間おきに動かすトリガーができます。

function createTrigger() {
  ScriptApp.newTrigger('pushInquiries').timeBased().everyHours(6).create();
}

時間で動くトリガーの時刻は、少しずらされることがあります。毎日9時に設定しても、9時から10時のあいだのどこかで動き、その後は毎日ほぼ同じ時刻になります。朝礼の9時ちょうどに最新にしておきたいなら、8時に設定します。

トリガーは、作った人のアカウントで動きます。作った人が異動や退職でそのアカウントを使えなくなると、トリガーも動かなくなると考えておきます。共有のアカウントで作るか、作った人をつなぎの一覧に書いておきます。

スクリプトがシートに書き込んでも、シートの編集で動くトリガーは動きません。スクリプトやAPIの操作ではトリガーが動かない仕様だからです。kintoneから書き出したシートの更新をきっかけに、続けて別の処理を動かす作りはできません。続けたい処理は同じ関数の中で順に呼びます。

【画面:Apps Scriptのトリガーの一覧。exportAnkenとpushInquiriesの2つが並んだ状態】

件数が増えたら差分にする

件数が増えて時間がかかるようになったら、前回の実行時刻をスクリプト プロパティに保存し、更新日時 > "2026-10-21T22:00:00Z" のような条件で取得して、シートの同じレコードIDの行を差し替えます。ただし差分の取り方では、kintoneで削除されたレコードがシートに残り続けます。週に一度は全件を取り直す関数を別に用意して、写しを作り直します。

連携サービスとiPaaSを使う

コードを持ちたくない会社は、連携サービスかiPaaSを使います。

連携サービスは、kintoneとスプレッドシートをつなぐための製品やプラグインで、サイボウズ以外の会社が提供しています。選ぶときは、向き、同期の頻度、キーを指定した上書きができるか、エラーがどこで分かるか、の4点を比べます。キーで上書きできない製品をシートからkintoneへの登録に使うと、二重登録の対策を別に考えることになります。

iPaaSは、複数のサービスを画面上でつなぐ道具です。Zapierにはkintoneの「New Record」をきっかけにする機能と、「Create Record」「Update Record by Update Key」などの登録と更新の機能があり、Googleスプレッドシートの行の追加や更新と組み合わせられます。Microsoft Power Automateは、kintoneヘルプに連携の設定方法が載っていて、レコードの追加や更新をきっかけにできます。Power Automateは有償プランの契約が要り、ゲストスペースのアプリとは連携できません。cybozu.comの管理者が共通管理で連携を許可しておく必要もあります。

どちらを使っても、APIのリクエスト数はkintone側で数えられ、同じアプリにつないだ仕組みの合計で上限に近づきます。

応用

Webhookでレコードの追加をすぐ送る

定期実行では、最大でトリガーの間隔ぶん遅れます。kintoneにレコードが追加されたらすぐシートに行を足したい、という場合は、kintoneのWebhookとApps Scriptのウェブアプリを組み合わせます。

  1. Apps Scriptに doPost(e) の関数を書き、e.postData.contents に届いたJSONから record を取り出してシートに1行足す処理にします。
  2. 右上の「デプロイ」から「新しいデプロイ」を選び、種類をウェブアプリにしてデプロイし、URLを控えます。
  3. kintoneの「アプリの設定」の「設定」タブで、「カスタマイズ/サービス連携」の「Webhook」をクリックします。
  4. 「追加する」をクリックし、「Webhook URL」に控えたURLを貼ります。先頭の https:// は外します。
  5. 「通知を送信する条件」で「レコードの追加」にチェックを入れます。
  6. 「保存」をクリックし、「アプリを更新」をクリックします。

届くJSONの type には ADD_RECORD や UPDATE_RECORD が入り、record はレコードを取得するAPIと同じ形です。

Webhookには注意点が3つあります。ExcelやCSVの読み込み、一括削除、REST APIでの一括の登録や更新では送られません。1ドメインあたり1分間に60件までで、それを超えた操作の分は送られません。1アプリに設定できるのは10個までです。送られない操作があるので、Webhookだけに頼らず、1日1回の全件の取り直しと組み合わせます。

制限

つなぎを作る前に、上限を確かめておきます。Apps Scriptの実行時間から下はGoogle側の上限です。

項目上限
1アプリあたりのAPIリクエスト数スタンダードコースは1日1万、ワイドコースは1日10万
同時に送れるAPIリクエスト1ドメインにつき100まで
1回に取得できるレコード500件まで(limit の初期値は100件)
取得の offset10,000まで
1回に登録、更新できるレコード100件まで
APIトークン1アプリ20個まで。1回のリクエストに指定できるのは9個まで
ファイルの読み込みCSVは100MB、10万行まで。Excel形式は1MB、1,000行まで
ファイルの書き出し100MBを超えると失敗
Apps Scriptの1回の実行時間6分
トリガーで動いた合計時間個人のGoogleアカウントは1日90分、Google Workspaceは1日6時間
UrlFetchAppの呼び出し個人のGoogleアカウントは1日2万回、Google Workspaceは1日10万回
トリガーの数1ユーザー1スクリプトあたり20
スプレッドシートの大きさ2,000万セルまたは100MBまで

1日1万リクエストは普通の使い方なら余裕があります。2万件を500件ずつ全件取っても1回40リクエストで、1時間おきでも1日960です。危ないのは1件ずつ送るループで、1,000行のシートなら1回で1,000リクエストを使います。必ずまとめて送ります。

6分の実行時間は、シートに1行ずつ書いているときに当たりやすい制限です。まとめて書いても当たるなら、差分の取得に切り替えます。

できないことと、その代わり

やりたいこと標準でできるか代わりの手
kintoneとシートを自動で同期するできない。標準の設定は無いApps Script、連携サービス、iPaaS
ライトコースでAPIトークンを使うできないCSVの書き出しと取り込みで回す。自動にするならスタンダードコースへ
添付ファイルをCSVで書き出すできないAPIでファイルを取得するスクリプトを書く。シートにはファイル名だけ載せる
関連レコード一覧をCSVで書き出すできない参照先のアプリを別に書き出し、シートで突き合わせる
計算フィールドやルックアップのコピー先にAPIで値を入れるできない計算の元のフィールドに値を入れる。ルックアップはキーの値を送る
ファイルの読み込みやAPIの一括処理でWebhookを送る送られない定期実行で全件を取り直す
シートの編集をスクリプトの書き込みで連鎖させるできない続く処理を同じ関数の中で呼ぶ
削除を差分で検知する差分の取得ではわからない週に一度、全件で作り直す
両方向の自動同期を安全に回す作れるが勧めない向きを片方向にし、正をkintoneに置く

よく詰まるところ

症状原因直し方
「ファイルに書き出す」が出てこないアプリのアクセス権で「ファイル書き出し」の権限がないアプリの管理者に権限を付けてもらう
シートに取り込むと文字化けするShift-JISで書き出している「文字コード」をUTF-8かBOM付きUTF-8にして書き出し直す
トークンを作ったのにエラーになる「アプリを更新」をしていない、またはトークンに必要な権限がないアプリを更新する。登録ならレコード追加とレコード編集にチェックを入れる
100件しか取れないlimit を書いていないlimit 500 を書き、500件ずつ繰り返す
1万件を超えると取れなくなるoffset の上限が10,000$id の昇順で前回の最後のIDより大きいものを取る
シートで金額が合計できないAPIの数値は文字列で返るNumber() で数にしてから書く
日時が9時間ずれるAPIの日時は協定世界時取得は new Date() に通す。登録は協定世界時に直して送る
同じ問い合わせが2件登録される追加のAPIで送っていて、途中で止まった行を送り直した受付IDで重複禁止にし、updateKey と upsert で送る
updateKey を指定するとエラーになるキーのフィールドが重複禁止になっていない、または種類が文字列(1行)か数値でない受付IDを文字列(1行)にして「値の重複を禁止する」をオンにする
100件まとめて登録できない1件の不正な値でリクエスト全体が取り消されるエラーの本文で該当の行を探して直す。必須フィールドの空も確かめる
ルックアップのキーを送るとエラーになる参照先のアプリのトークンも要る両方のアプリのトークンをカンマ区切りで X-Cybozu-API-Token に入れる
実行が6分で止まるシートへの書き込みを1行ずつしている、または件数が多いsetValues でまとめて書く。差分の取得にする
ある日から自動で動かなくなったトリガーを作った人のアカウントが使えなくなった実行の記録を見て、共有のアカウントで作り直す
社外からつながらないcybozu.comでIPアドレスの制限をかけているシステム管理者に、Apps Scriptからの接続をどう通すか相談する

次にやること

APIの呼び方そのもの、トークンの権限の考え方、クエリの書き方を一通り押さえたいときは「kintone REST APIの使い方。APIトークンの発行からレコードの取得・登録まで」が続きです。いまシートやExcelで回している管理表をkintoneに移してからつなぐなら、「Excelの管理表をkintoneに移す手順。取り込みで崩れない整え方」を先に読むと、取り込みで列が崩れるのを避けられます。予定をカレンダーに出したいときは「kintoneとGoogleカレンダーの連携。予定を二重に入れない作り方」、kintoneの画面の側でボタンを押したときにシートへ送る、といった動きを入れたいときは「kintoneのJavaScriptカスタマイズ入門。最初の1本を動かすまで」に進みます。

あわせて読む