Notionの更新履歴を自動でSlackに週次報告する方法

Notionでチームの情報を管理していると、週ごとに「誰が何を更新したか」を把握したくなる瞬間が必ず来ます。本記事では、Notionの更新を自動で蓄積し、週次でSlackにまとめて通知、通知後に蓄積をリセットする仕組みを、Google Apps Script(GAS)を使ってノンプログラマでも実装できるレベルで丁寧に解説します。準備するものはNotionのIntegration、SlackのIncoming Webhook、Googleアカウントだけ。手順を一度整えれば、毎週のチェック作業を自動化してチームの見える化がぐっと楽になります。

当ブログがオススメする

業務自動化サービスランキング

なお、業務効率化や工数削減を目指しているものの、どの業務から自動化すべきか、どのツールや手段が自社に合っているのかがあいまいな方は、「業務自動化プラン診断」をお試しください。

かかる時間は1分ほど。4つの質問に答えるだけで、あなたに最適な自動化対象業務や、推奨される自動化手段を診断してもらえます。

効率よく自社に適した業務効率化を知りたい方は、ぜひ一度お試しください。

\ 4つの質問に答えるだけ /

目次

完成形イメージ

こんなシーンでの活用に適しています

主に、Notionを日々更新している、かつ履歴を記録したいシーンで役に立ちます!

  1. 週報作成の省力化 — 各メンバーのNotion更新を手作業で集めて週報にまとめているチーム。
  2. リモートチームの状況確認 — 毎週Slackで更新有無を把握して、ミーティングの議題決めに使いたい場合。
  3. ナレッジ管理の追跡 — ドキュメントが増える週に、どのページが編集されたかを一覧化したいとき。
  4. 承認ワークフローの補助 — ステータス変更など「重要なプロパティが更新された」ことを週次で把握したい場合(差分拡張で対応可)。
  5. 小〜中規模チームの監査ログ — 毎週の編集ログを保管しておくことで、後から誰がいつ編集したか確認できる。
  6. 外部ツールを使わず社内で完結させたい場合 — Googleの無料機能中心で安価に運用したいとき。

Notionの更新履歴を自動でSlackに週次報告する方法のメリットや特徴

メリット低コストで始められる
デメリット「何が変わったか(差分)」を自動で出すには追加の設定が必要
難易度・面倒さ低〜中程度
特徴シンプルで拡張しやすい構成
価格無料(規模によっては一部有料)

用意するもの

①Notion アカウント
②Slack ワークスペース
③Google アカウント

設定手順

1. Notion 側の準備

1-1.ブラウザで Notion にログイン。

1-2.Integrationを作成する(Notion の「My integrations」ページへ行く必要があります)。

ブラウザで https://www.notion.so/my-integrations にアクセスする/もしくは Notion の設定メニューから「Integrations(統合)」を探す。

1-3.「新しいインテグレーション」を押す。

1-4.名前を付ける(例:weekly-reporter)。

1-5. 作成後、「Internal Integration Token」が表示されるのでコピーして安全な場所へ保存

後で NOTION_TOKEN に使うので、コピペしておきましょう!

1-6. 対象の データベースページ(Notion の Database)を開く。

1-7. 右上の ⋯ ボタンを押し、「接続」から先ほど作ったweekly-reporterを追加する。これにより Integration がデータベースを読めるようになります。

1-8. データベースIDの取得

https://www.notion.so/XXXXXXXX?v=YYYYYYYY

上記URLでいう、XXXXXXXX の部分が「データベースID」になります。ここの部分もコピペしておきましょう。

2. Slack 側の準備

今回はまっさらなワークスペースを作成して手順を説明しています。Slackの権限によっては「アプリを追加する」の項目が出ないこともあるかもしれません。その場合は管理しているIT部門に確認してください。

2-1.Slack のワークスペースで、アプリを追加します。

2-2.「Incoming Webhooks」を検索して追加(Add to Slack)。

2-3.インストールしようとするとブラウザに飛びます。

4.画面に沿って進めます。

5.Webhook を作る際に通知先のチャンネルを選択し、Webhook URL(長い URL)をコピーして保存。これが SLACK_WEBHOOK_URL になります。

3. Google スプレッドシートの準備

3-1. Google ドライブで新しいスプレッドシートを作成。名前は Weekly_Log などにする。

3-2. シートの1行目(ヘッダ)を作る。以下を1行目(A1〜E1)に入れてください:

  • A1: RecordedAt
  • B1: PageTitle
  • C1: Editor
  • D1: PageURL
  • E1: LastEditedTime

※ご使用の内容に合わせて変更してください。

3-3. スプレッドシートの URL の中にある spreadsheetId をコピー(URL の /d/ と /edit の間)。これが SPREADSHEET_ID です。

3-4. スプレッドシートの ファイル → 設定タイムゾーン を Asia/Tokyo に設定してください(週次トリガーの時間が日本時間で動くようにするため)。

4. Apps Script にコードをセット

ここからは少し「むずかしいかも?」、「取っ付きにくそう」と感じる方もいるかも知れませんが、作業としてはコピペかマウスで選択するかくらいなので、安心して進めてくださいね。

4-1. スプレッドシートのメニューから 拡張機能 → Apps Script を開く(新しいタブで Apps Script エディタが開きます)。

4-2. 以下のコードをまるごと貼り付けます。

下のコードは「基本機能(蓄積 → 週次送信 → 送信後クリア)」を実装し、初心者にも分かるようコメントを多めにしています。貼り付けてそのまま動かせます(ただし後述の設定値を入力する必要があります)。

// ---- Notion → Google Sheets に蓄積、週次で Slack に送信してクリアするサンプル ----
// 使い方(簡易):
// 1) 以下の設定値をスクリプトプロパティに登録(またはコード先頭に直接埋めても良い。推奨はスクリプトプロパティ):
//    NOTION_TOKEN, DATABASE_ID, SPREADSHEET_ID, SLACK_WEBHOOK_URL
// 2) トリガーを設定:
//    - pollNotionAndAppend を「時間主導」で例えば毎時実行
//    - sendWeeklyReportToSlack を「週次」で任意の曜日/時間に実行
// 3) 最初は手動で関数を実行して動作確認してください。

/* ---------- ユーティリティ: 簡単なログ表示 ---------- */
function logLine(msg) {
  Logger.log(msg);
}

/* ---------- Notion を問い合わせてデータベースをページネーション付きで取得 ---------- */
function fetchNotionDatabaseQuery(notionToken, databaseId, startCursor) {
  const url = 'https://api.notion.com/v1/databases/' + databaseId + '/query';
  const headers = {
    'Authorization': 'Bearer ' + notionToken,
    'Notion-Version': '2022-06-28',
    'Content-Type': 'application/json'
  };
  const payload = startCursor ? JSON.stringify({start_cursor: startCursor}) : JSON.stringify({});
  const options = {
    method: 'post',
    headers: headers,
    payload: payload,
    muteHttpExceptions: true
  };
  const resp = UrlFetchApp.fetch(url, options);
  const code = resp.getResponseCode();
  if (code < 200 || code >= 300) {
    throw new Error('Notion API error: ' + code + ' / ' + resp.getContentText());
  }
  return JSON.parse(resp.getContentText());
}

/* ---------- ページのタイトルを安全に取り出す ---------- */
function extractTitleFromProperties(props) {
  // Notion の title プロパティの取り方はプロパティ名が環境で違うことがあるため、
  // 全プロパティを走査して type === 'title' を探す
  for (let key in props) {
    if (!props.hasOwnProperty(key)) continue;
    const p = props[key];
    if (p && p.type === 'title') {
      const arr = p.title || [];
      return arr.map(r => r.plain_text).join('') || '(no title)';
    }
  }
  // fallback
  if (props.Name && props.Name.title) {
    return props.Name.title.map(r => r.plain_text).join('') || '(no title)';
  }
  return '(untitled)';
}

/* ---------- 定期実行:Notion をチェックしてシートに追加する ---------- */
function pollNotionAndAppend() {
  const props = PropertiesService.getScriptProperties();
  const NOTION_TOKEN = props.getProperty('NOTION_TOKEN');
  const DATABASE_ID = props.getProperty('DATABASE_ID');
  const SPREADSHEET_ID = props.getProperty('SPREADSHEET_ID');

  if (!NOTION_TOKEN || !DATABASE_ID || !SPREADSHEET_ID) {
    throw new Error('必要な設定値がありません。スクリプトプロパティに NOTION_TOKEN, DATABASE_ID, SPREADSHEET_ID を設定してください。');
  }

  // 最後にチェックした時刻を保存しておき、これ以降に編集されたものだけを取る
  const lastChecked = props.getProperty('LAST_CHECKED') || new Date(0).toISOString();
  const nowIso = new Date().toISOString();

  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();

  let startCursor = null;
  do {
    const respJson = fetchNotionDatabaseQuery(NOTION_TOKEN, DATABASE_ID, startCursor);
    startCursor = respJson.next_cursor;
    const results = respJson.results || [];
    results.forEach(page => {
      const pageEdited = page.last_edited_time;
      if (pageEdited > lastChecked) {
        // 抽出
        const title = extractTitleFromProperties(page.properties || {});
        const url = page.url || ('https://www.notion.so/' + page.id.replace(/-/g,''));
        let editor = '';
        try {
          if (page.last_edited_by && page.last_edited_by.type === 'person') {
            editor = page.last_edited_by.person.name || page.last_edited_by.id || '';
          } else if (page.last_edited_by && page.last_edited_by.name) {
            editor = page.last_edited_by.name;
          } else {
            editor = '';
          }
        } catch (e) {
          editor = '';
        }
        // 重複防止のため、すぐに同じ page.id と lastEdited が既にあるか確認できる処理を入れるとより安全です(後述)
        sheet.appendRow([new Date().toISOString(), title, editor, url, pageEdited]);
        logLine('Appended: ' + title);
      }
    });
  } while (startCursor);

  // チェック時刻を更新(成功時)
  props.setProperty('LAST_CHECKED', nowIso);
}

/* ---------- 週次処理:シートの内容を Slack に送信し、成功したらシートをクリア ---------- */
function sendWeeklyReportToSlack() {
  const props = PropertiesService.getScriptProperties();
  const SPREADSHEET_ID = props.getProperty('SPREADSHEET_ID');
  const SLACK_WEBHOOK_URL = props.getProperty('SLACK_WEBHOOK_URL');

  if (!SPREADSHEET_ID || !SLACK_WEBHOOK_URL) {
    throw new Error('必要な設定値がありません。スクリプトプロパティに SPREADSHEET_ID と SLACK_WEBHOOK_URL を設定してください。');
  }

  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
  const rows = sheet.getDataRange().getValues();
  if (rows.length <= 1) {
    logLine('No updates to send this week.');
    return;
  }
  const header = rows[0];
  const data = rows.slice(1);

  // Slack に投げるテキストを作る(短め)
  let text = '*Notion 更新週次レポート*\n';
  text += '期間: ' + getWeekRangeText() + '\n\n';
  data.forEach(r => {
    const recordedAt = r[0];
    const title = r[1];
    const editor = r[2] || '不明';
    const url = r[3];
    const lastEdited = r[4];
    text += `• ${title} (編集: ${editor})\n  ${url}\n  最終編集: ${lastEdited}\n\n`;
  });

  const payload = JSON.stringify({text: text});
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: payload,
    muteHttpExceptions: true
  };
  const resp = UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
  const code = resp.getResponseCode();
  if (code >= 200 && code < 300) {
    // 成功したらヘッダ行を残して削除
    if (sheet.getLastRow() > 1) {
      sheet.deleteRows(2, sheet.getLastRow()-1);
    }
    logLine('Slack への送信成功。シートをクリアしました。');
  } else {
    logLine('Slack webhook failed: ' + code + ' / ' + resp.getContentText());
    throw new Error('Slack に送信できませんでした。レスポンスコード: ' + code);
  }
}

/* ---------- 補助: 今週の期間を返す(見出し用) ---------- */
function getWeekRangeText() {
  const now = new Date();
  // 日曜始まりを仮定
  const day = now.getDay();
  const start = new Date(now);
  start.setDate(now.getDate() - day);
  const end = new Date(start);
  end.setDate(start.getDate() + 6);
  const tz = Session.getScriptTimeZone();
  return Utilities.formatDate(start, tz, 'yyyy-MM-dd') + ' 〜 ' + Utilities.formatDate(end, tz, 'yyyy-MM-dd');
}

4-3. コードを無事に貼り付けられたら保存しましょう。

5. 設定値の登録方法

5-1. Apps Script エディタで左側メニューの「プロジェクトの設定」を押す。

5-2. 少し下にスクロールして「スクリプト プロパティを追加」を押して、以下の4つのプロパティを追加します。

  • NOTION_TOKEN = (Notion で取得したシークレットトークン)
  • DATABASE_ID = (Notion データベースID)
  • SPREADSHEET_ID = (作成したスプレッドシートのID)
  • SLACK_WEBHOOK_URL = (Slack の Webhook URL)

5-3. 無事すべて追加できたら保存する。

6. トリガー(自動実行)の設定

6-1. 左側メニューの「トリガー」をクリック。

6-2. 「トリガーを追加」をクリックして1つ目のトリガーを作成します。

  1. 関数を選択:pollNotionAndAppend
  2. 実行するデプロイ:Head(デフォルト)
  3. イベントのソース:時間主導型
  4. 時間ベースのトリガータイプ:分ベースのタイマー / 時間ベースのタイマー(推奨は「時間ベース」)
  5. 間隔:1時間おき(または運用に合わせて2時間毎など)
  6. 保存

6-3. 更にもう一つ別のトリガーを作成します。

  1. 関数:sendWeeklyReportToSlack
  2. イベントのソース:時間主導型 → 週ベースのタイマー
  3. 曜日と時刻:例:毎週月曜 9時~10時
  4. 保存

6-4. 上記のようにトリガー2つが設定できたら完了です。

初回は Apps Script が Google アカウントへのアクセス許可を求めます。権限ダイアログが出たら指示に従って承認してください(スクリプトがスプレッドシート編集や外部 API 呼び出しをするための許可です)。

7. 動作確認

ここまでくれば、設定は完了です。動作確認をして想定通りに動くかを見ます。

7-1. Apps Script エディタで pollNotionAndAppend を選んで ▶(実行)を押します。

成功すれば、スプレッドシートに追加されます。

スプレッドシートを確認して行が入っていることを確認。

7-2. 次はApps Script で sendWeeklyReportToSlack を手動実行します。

Slack の指定チャンネルにレポートが届くか確認します。以下のように届けば無事成功です。

シートは送信成功後にスプレッドシートの中身がクリアされ、ヘッダだけ残ります。

よくある質問

「何が変わったか(差分)」まで自動で取れますか?

Notion APIはページの「直前の編集差分」を直接返さないため、差分を出すには前回のスナップショットを保存して比較する仕組みが必要です。サンプルコードはまず「更新があったページ」を収集するところまで実装してあり、差分出力はオプションで追加できます。

複数のデータベースをまとめて監視できますか?

可能です。Database IDごとにポーリング処理を回すか、1つのGAS関数で複数DBを順に問い合わせる形に拡張してください。

誰でも設定できますか?

はい。手順に忠実に従えば実装可能です。つまずきやすい箇所(Integrationの共有、トリガーの権限承認)を丁寧にフォローすれば現場の非エンジニアでも運用できます。

なかなかうまくいかないときは?

プログラミングが未経験の方にとっては少しハードルが高く「諦めるしかない⋯」と挫折するきっかけを生みかねません。

「社内で自動化したは良いものの、自分がやめたら引き継ぐ人がいない⋯」

「一つ自動化したら、他部署からも自動化を依頼されて自分の仕事が進まない⋯」

と不安な方もいますよね。

そこで、おすすめしたいのが「ジドウカ」です。

ジドウカは、これまで合計800タスク以上の業務の自動化をしてきた実績のある法人専用の自動化サービスです。

業務の一部を“タスク単位”で自動化し、【月額1万円から】安定運用できるサブスクリプション型のサービスです。 タスクを外注するため手離れもよく、技術のことが分からなくても、「こういう作業をラクにしたい」と伝えるだけで自動化することが可能です。

「わたしが自動化したい内容って自動化できるんだろうか⋯」という方には、少額・短期間での「お試し開発」があるので、お気軽にご活用ください。

まとめ

Notion の更新を自動で収集し、週次で Slack に通知する仕組みは、初期設定さえ済ませれば「週報作成の時間削減」「チームの変更可視化」「低コストでの運用」を実現できる現実的な自動化施策です。今回の手順と添付の Apps Script を使えば、ITリテラシーが高くない方でも段階的に導入できますが、差分表示や大量ページの高頻度監視といった高度な要件は追加実装が必要になる点に留意してください。まずはサンドボックスで動作確認を行い、バックアップ(アーカイブ)を有効にしたうえで本番運用に移すのがおすすめです。

自社で自動化する際によくある失敗ランキング

自動化ツールを導入すれば業務が自動化され、効率が劇的に向上する——。 そう考えている企業は多いですが、実際には多くの企業が自動化ツールを十分に活用できていません。 有名な自動化ツールであるRPAを例にあげても、導入した企業の実態は理想と大きく異なった結果となっています。

RPA導入企業の約60%が「あまり活用できていない」と回答

多くの企業がRPAを導入しているにも関わらず、約60%の企業が「期待したほど活用できていない」と感じているというデータです。これは、「導入しただけでは、業務改善につながらない」という現実を示しています。

RPAの効果を実感できない要因は『RPA開発が進んでいない』

「RPAの効果を実感できていない」と回答した企業の多くが、その理由として「RPA開発が進んでいない」「他業務・他部署への展開ができていない」ことを挙げています。   「〇〇業務はツールを導入すればすぐにラクになるはず」と思って、自社で自動化に挑戦した方も多いのではないでしょうか?しかし私たちには、こんな“あるあるの失敗談”がよく届きます。

🥇 第1位:初期設定でつまずき、結局断念…

思っていたより設定が複雑で、ツールの仕様を理解する前に挫折してしまうケース。 特にRPAツールやノーコードツールは、「慣れるまでが大変」という声が多いです。

🥈 第2位:担当者が辞めて、運用不能に…

担当者が社内で唯一のキーマンだった場合、その人がいなくなると全て止まってしまうという問題が発生します。 しかも、「誰も中身が分からないから触れない」という状況になりがち。

🥉 第3位:不具合や修正対応に時間がかかる…

自動化が止まったとき、「誰が見ればいいのか分からない」「ベンダーに相談するのも手間」という理由で、対応が後手に。 気づけばその対応に何時間も時間を取られ、本業に集中できなくなってしまうことも…。   実はよくある…自社で自動化に挑戦したときの“落とし穴” 共通するのは「すべて自社で完結しようとした」こと。 このようなケースに共通するのが、「最初から最後まで、すべて自社で完結しようとした」点です。 最初はうまくいっても、長期的に安定した自動化運用には、継続的な保守や柔軟な調整が不可欠です。

安定的に自動化したいならジドウカがおすすめ

 「ツールを入れただけ」では業務はラクになりません 「業務をラクにする自動化」のためには、設定・運用・トラブル対応まで含めてプロに任せるのが最も確実です。

ジドウカとは?

業務の一部を“タスク単位”で自動化し、月額で安定運用できるサブスクリプション型のサービスです。 技術のことが分からなくても、「こういう作業をラクにしたい」と伝えるだけでOK。

ジドウカでできること(業務例)

・定期レポートの自動作成とSlack送信 ・受注データのExcel整形とkintone登録 ・競合サイトの自動モニタリングとアラート通知 ・営業リストの自動生成とCRMへの投入 など

ジドウカが選ばれる理由

弊社の自動化サービス「ジドウカ」は、1社1社、1タスク1タスクに合わせて完全オーダーメイドで開発するサービス担っています。
  • ヒアリングから開発・運用まで丸ごとサポート
  • トラブル発生時には即時対応
  • 月額料金内で自由に修正をご依頼可能
実際に多くのお客様から「自社での自動化運用に失敗した後に依頼してよかった」と高評価をいただいています。
目次