回答データの連携
スプレッドシートに回答を送る
Googleスプレッドシートへの直接連携(Google認証)は行っていませんが、Google Apps Scriptで簡単な中継スクリプトを作ることで、無料でスプレッドシートへの自動記録が実現できます。
1. 記録先のGoogleスプレッドシートを用意する
新規、または既存のGoogleスプレッドシートを開きます。
開いたときのURL(
https://docs.google.com/spreadsheets/d/スプレッドシートID/edit)に含まれる「スプレッドシートID」の部分を控えておきます。手順2で使います。2. Apps Scriptを作成する
スプレッドシートのメニューから「拡張機能」→「Apps Script」を開き、デフォルトのコードを消して以下を貼り付けます。
SPREADSHEET_IDの値は、手順1で控えたスプレッドシートIDに置き換えてください。function doPost(e) { // 記録先のスプレッドシートIDを指定します。スプレッドシートを開いたときのURLの // https://docs.google.com/spreadsheets/d/【ここ】/edit の部分です。 var SPREADSHEET_ID = "ここにスプレッドシートIDを貼り付け"; var data = JSON.parse(e.postData.contents); // complete: 回答完了時 / progress: 回答ごとの途中経過(「回答ごとに送信」設定時のみ届く) if (data.event !== "complete" && data.event !== "progress") { return ContentService.createTextOutput(JSON.stringify({ ok: true })).setMimeType(ContentService.MimeType.JSON); } // 回答ごとの送信は同じ訪問から短い間隔で続けて届くため、同時に処理して行が重複しないようロックする。 var lock = LockService.getScriptLock(); lock.waitLock(30000); try { var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheetByName("回答") || ss.insertSheet("回答"); var FIXED_HEADERS = ["送信日時", "pageId", "source", "送信元URL", "セッションID", "ステータス", "最終更新日時"]; // 1行目(ヘッダー行)を読み込む。まだ無ければ固定列だけで作成する。 var lastColumn = sheet.getLastColumn(); var headers = lastColumn > 0 ? sheet.getRange(1, 1, 1, lastColumn).getValues()[0] : []; if (headers.length === 0) { headers = FIXED_HEADERS.slice(); sheet.getRange(1, 1, 1, headers.length).setValues([headers]); } // 固定列・質問ラベル(answer.name)列とも、ヘッダーに無ければ末尾に列を追加する。 // フローを編集して質問が増えたときだけでなく、スクリプト更新で固定列が増えたときも、 // 既存の列は上書き・並べ替えせず末尾に追加するだけにすることで、以前から使っているシートを壊さない。 FIXED_HEADERS.concat(data.answers.map(function (answer) { return answer.name; })).forEach(function (name) { if (headers.indexOf(name) === -1) { headers.push(name); sheet.getRange(1, headers.length).setValue(name); } }); // 同じ訪問(セッションID)の行が既にあれば、その行を上書きする(1訪問=1行)。 var rowIndex = -1; if (data.sessionId && sheet.getLastRow() > 1) { var found = sheet .getRange(2, headers.indexOf("セッションID") + 1, sheet.getLastRow() - 1, 1) .createTextFinder(data.sessionId) .matchEntireCell(true) .findNext(); if (found) rowIndex = found.getRow(); } // 現在のヘッダーの並びに合わせて1行分のデータを組み立てる(列がずれないように)。 var now = new Date(); var row; if (rowIndex === -1) { row = new Array(headers.length).fill(""); row[headers.indexOf("送信日時")] = now; } else { row = sheet.getRange(rowIndex, 1, 1, headers.length).getValues()[0]; } row[headers.indexOf("pageId")] = data.pageId; row[headers.indexOf("source")] = data.source; row[headers.indexOf("送信元URL")] = data.sourceUrl || ""; row[headers.indexOf("セッションID")] = data.sessionId || ""; row[headers.indexOf("最終更新日時")] = now; // 完了済みの行は、通信の順序が前後して後から届いた途中経過で「回答中」に戻さない。 var statusIndex = headers.indexOf("ステータス"); if (row[statusIndex] !== "完了") { row[statusIndex] = data.event === "complete" ? "完了" : "回答中"; } data.answers.forEach(function (answer) { row[headers.indexOf(answer.name)] = answer.value; }); if (rowIndex === -1) { sheet.appendRow(row); } else { sheet.getRange(rowIndex, 1, 1, headers.length).setValues([row]); } } finally { lock.releaseLock(); } return ContentService .createTextOutput(JSON.stringify({ ok: true })) .setMimeType(ContentService.MimeType.JSON); }3. ウェブアプリとしてデプロイする
Apps Scriptエディタ右上の「デプロイ」→「新しいデプロイ」を選び、種類として「ウェブアプリ」を選択します。
以下の設定にしてください。
- 実行するユーザー: 自分
- アクセスできるユーザー: 全員
「デプロイ」をクリックすると、
https://script.google.com/macros/s/.../execという形式のURLが発行されます。このURLをコピーしておきます。スクリプトの内容を変更した場合は、「デプロイを管理」から既存のデプロイを「編集」し、 バージョンを「新バージョン」にして再デプロイしないと変更が反映されません。4. chachat.page側にURLを登録する
ビルダーの「設定」タブ →「外部サービス連携」→「スプレッドシート」カードで、以下のように登録します。
- 送信先URL: 手順3で発行されたURL
保存後、「テスト送信」ボタンでスプレッドシートに行が追加されることを確認してください。
送信タイミングについて
スプレッドシートカードの「送信タイミング」で、記録するタイミングを選べます。
- 完了時のみ送信:会話を最後まで進めた訪問者の回答だけが、完了時に1行追加されます(ステータスは「完了」)。
- 回答ごとに送信:質問に答えるたびに、その訪問者の行が作成・更新されます。途中で離脱した訪問者の回答も ステータス「回答中」として残り、最後まで進むと同じ行が「完了」に変わります。
シークレットについて
スプレッドシート連携の「シークレット」を設定すると、送信時にAuthorization: Bearer <シークレット>ヘッダーが付与されます。ただしGoogle Apps ScriptのdoPost関数はリクエストヘッダーを読み取れないため、この方式では検証できません。 第三者からの不正な呼び出しを防ぎたい場合は、シークレットの代わりに送信先URLの末尾へ任意のトークンをクエリパラメータとして付与し (例: …/exec?token=あなたが決めた文字列)、 スクリプト内でe.parameter.tokenを検証する方法をご利用ください。