Notionの新規記事が公開されたら自動で社内Slackにお知らせする方法

Notionで記事を管理していると、「公開された瞬間に関係者へ知らせたい」と思う場面は多いのではないでしょうか。公開の連絡をメールやチャットで個別に送るのは手間がかかり、漏れも発生しがちです。この記事では、Notionの新規記事公開を自動でSlackに通知する方法を紹介します。Google Apps Script(GAS)を使うことで、ITに詳しくない方でも仕組みを簡単に導入できます。導入後は、記事公開と同時に自動でSlackに通知が送られるため、業務のスピードアップと連絡漏れ防止につながります。

当ブログがオススメする

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

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

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

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

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

目次

完成形イメージ

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

①社内ブログやナレッジ記事を公開した際に、担当部署へ即座に共有したいとき
②外部公開前の記事を社内チェック用チャンネルに流し、レビュー依頼を簡単にしたいとき
③定期的な広報記事やお知らせの公開を、広報・営業・経営層に迅速に伝えたいとき

プレスリリースやニュースリリースなど更新頻度が多い記事業務の場合は、自動的にレビュー依頼が飛ぶため、効率化できます。

Notionの新規記事が公開されたら自動で社内Slackにお知らせする方法

メリット通知漏れがなくなり、公開作業が効率化できる。
デメリット初期設定にAPIやGASの知識が少し必要。
難易度・面倒さ初心者でも手順通りに進めれば実現可能だが、最初はやや煩雑。
特徴NotionとSlackを無料サービスだけで連携でき、完全自動化できる。
価格無料で導入可能

用意するもの

①Notion(記事データベース)
②Slack(通知先チャンネル)
③Google アカウント(GAS実行用)

設定手順 0. 事前に決める3つ

  • 通知先Slackチャンネル(例:#レビューチャンネル)
  • タイトル(既定で「名前」になっていることが多い)
    • Notionの記事データベースのプロパティ名
    • ステータス(「下書き/レビュー中/公開」など)
    • 公開日時(Date型)
    • (あれば)公開URL(URL型 or Formula型でもOK)
  • 通知にメンションが必要か(@here、<@UXXXX> など)

今回は以下のようなデータベースにしています。

名前ステータス公開日時公開URL(任意)作成者(任意)カテゴリ(任意)
タイトル型(既定)ステータス型(またはセレクト型)日付(Date)URL型 / Formula型People型セレクト型
内容・用途記事タイトルを入力記事の進行状況を管理実際に公開する日時を入力外部公開した記事のURLを記録記事担当者を管理記事の分類に利用
設定例社内ニュース 2025年9月号下書き / レビュー中 / 公開2025/09/16 10:00https://example.com/news/20250916山田 太郎お知らせ / コラム / プレスリリース

1. Notion の準備

まずはNotion側から設定していきます。データベースにインテグレーションを連携させていきます。これによって、他のツールと連携できるようになります。

1-1. インテグレーション作成

Notion画面右上のプロフィール画像 → Settings → Connections → Develop or manage integrations を開く

+ New integration
Name:任意(例:GAS Slack Notifier)
Capabilities:デフォルトでOK(content: read が必須)
Internal Integration Token(例:ntn_xxx)を控える

1-2. 記事データベースをインテグレーションに共有

記事DBを開く(テーブル表示)

右上の …(三点)→ Add connections
さきほど作ったインテグレーション名を検索→Connect

これを忘れると 404(object_not_found) になります(最頻出のつまずき)

1-3. データベースIDを控える

記事DBを開いた状態で、右上 Share → Copy link
クリップボードのURL中から データベースID を抜き出す
NotionのURLの中でXXXの部分:https://www.notion.so/XXX?v=YYY

2. Slack の準備(いちばん簡単:Incoming Webhook)

次はSlack側の設定です。英語ばかりのページなので、ブラウザの翻訳機能などを使って落ち着いて真似していってください。

こちらからSlackで Appを追加

From scratchを選択

Incoming Webhooksを開く

ONにします。

Add New Webhookを実行します。

通知先チャンネルを選びます。

発行された Webhook URL(https://hooks.slack.com/services/…)を控える

3. GAS プロジェクト作成

GASでここまで設定したNotionとSlackをつなげていきます。コードを入力しますが、コピペでOKです。

ブラウザで https://script.google.com/ を開く

新しいプロジェクト を作成

コード.gs に下のコードを丸ごと貼り付け

3-1. スクリプトプロパティを設定

メニュー (歯車)プロジェクトのプロパティ → スクリプトのプロパティ を開き、以下を追加

プロパティ名値の例
NOTION_TOKENntn_xxx(Notionのインテグレーショントークン)
NOTION_DATABASE_IDxxxxxxxxxxxxxxxxxxxxxxxxxxx(NotionのURLの中でXXXの部分:https://www.notion.so/XXX?v=YYY)
SLACK_WEBHOOK_URLhttps://hooks.slack.com/services/XXX/YYY/ZZZ
SLACK_MENTION@here または <@U123456>(任意。空でもOK)
DRY_RUNtrue(最初はテストモード推奨。あとで削除かfalseに)

DRY_RUN=trueだと、Slackには送らず、ログにだけ「こう送ります」を出します。
安全に動作確認してから、本番化しましょう。

4. コード(Webhook版・そのままコピペOK)

/** Notion → GAS(定期)→ Slack 通知(Webhook版)
 *  条件:
 *   - ステータス = 「公開」
 *   - 公開日時 > 前回チェック時刻
 *  重複通知防止:
 *   - 通知済みページIDをスクリプトプロパティに保存
 */


const SP = PropertiesService.getScriptProperties;


function CONF() {
  const p = SP().getProperties();
  return {
    NOTION_TOKEN: p.NOTION_TOKEN,
    NOTION_DATABASE_ID: p.NOTION_DATABASE_ID,
    SLACK_WEBHOOK_URL: p.SLACK_WEBHOOK_URL,
    SLACK_MENTION: p.SLACK_MENTION || "",
    DRY_RUN: String(p.DRY_RUN || "").toLowerCase() === "true",
    TZ: "Asia/Tokyo",
    PAGE_SIZE: 20,           // 1回の取得件数
    FIRST_LOOKBACK_HOURS: 24 // 初回のみ「何時間前まで」さかのぼるか
  };
}


// ===== エントリーポイント(トリガー用) =====
function pollNotionAndNotify() {
  const conf = CONF();
  assertRequired(conf);


  // 初回は少しだけさかのぼり、それ以降は前回時刻から
  const lastCheckedAt =
    SP().getProperty("LAST_CHECKED_AT") ||
    new Date(Date.now() - conf.FIRST_LOOKBACK_HOURS * 60 * 60 * 1000).toISOString();


  const notifiedMap = JSON.parse(SP().getProperty("NOTIFIED_MAP") || "{}"); // {pageId:true}


  // 取得(必要なら複数ページ分を繰り返し取得)
  const pages = fetchPublishedPagesSinceAll(lastCheckedAt, conf);


  // 未通知だけ
  const newPages = pages.filter(p => !notifiedMap[p.id]);


  // 送信
  newPages.forEach(page => {
    if (conf.DRY_RUN) {
      console.log("[DRY_RUN] Would notify:", page);
      notifiedMap[page.id] = true; // 動作確認では既読扱いにしておくと重複防止の挙動も確認しやすい
      return;
    }
    try {
      postToSlackWebhook(page, conf);
      notifiedMap[page.id] = true;
    } catch (e) {
      console.error("Slack通知に失敗:", page, e);
    }
  });


  // 保存
  SP().setProperty("NOTIFIED_MAP", JSON.stringify(notifiedMap));
  SP().setProperty("LAST_CHECKED_AT", new Date().toISOString());
}


// ===== Notion API:since以降の公開記事を全件とる(20件超の保険)=====
function fetchPublishedPagesSinceAll(sinceIso, conf) {
  let cursor = null;
  const all = [];
  do {
    const chunk = fetchPublishedPagesSince(sinceIso, conf, cursor);
    all.push(...chunk.results);
    cursor = chunk.next_cursor;
  } while (cursor);
  return all;
}


function fetchPublishedPagesSince(sinceIso, conf, startCursor) {
  const url = `https://api.notion.com/v1/databases/${conf.NOTION_DATABASE_ID}/query`;
  const headers = {
    "Authorization": `Bearer ${conf.NOTION_TOKEN}`,
    "Notion-Version": "2022-06-28",
    "Content-Type": "application/json",
  };


  const payload = {
    page_size: conf.PAGE_SIZE,
    filter: {
      and: [
        { property: "ステータス", status: { equals: "公開" } },
        { property: "公開日時", date: { after: sinceIso } }
      ]
    },
    sorts: [{ property: "公開日時", direction: "ascending" }]
  };
  if (startCursor) payload.start_cursor = startCursor;


  const res = UrlFetchApp.fetch(url, {
    method: "post",
    headers,
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  });
  if (res.getResponseCode() >= 300) {
    throw new Error(`Notion API error: ${res.getResponseCode()} / ${res.getContentText()}`);
  }


  const data = JSON.parse(res.getContentText());
  const results = (data.results || []).map(page => shapePage(page));
  return { results, next_cursor: data.has_more ? data.next_cursor : null };
}


function shapePage(page) {
  const props = page.properties || {};
  const title = extractTitle(props);
  const publishedAt = props["公開日時"]?.date?.start || null;
  const link = extractPublicUrl(props) || page.url; // 公開URLがあれば使う。なければNotion内部URL
  return { id: page.id, title, publishedAt, url: link };
}


function extractTitle(props) {
  // 「名前」「タイトル」どちらでも拾う。なければ最初のtitle型を検索。
  const cand = props["名前"] || props["タイトル"] || Object.values(props).find(p => p.type === "title");
  const arr = cand?.title || [];
  const txt = arr.map(t => t.plain_text).join("").trim();
  return txt || "(無題)";
}


function extractPublicUrl(props) {
  const p = props["公開URL"] || props["URL"] || null;
  if (!p) return null;
  if (p.type === "url") return p.url || null;
  if (p.type === "rich_text") {
    const s = (p.rich_text || []).map(t => t.plain_text).join("").trim();
    return s || null;
  }
  if (p.type === "formula" && p.formula?.string) return p.formula.string || null;
  return null;
}


// ===== Slack(Incoming Webhook)=====
function postToSlackWebhook(page, conf) {
  const lines = [
    conf.SLACK_MENTION ? `${conf.SLACK_MENTION} 新規記事が公開されました!` : "新規記事が公開されました!",
    `*タイトル*: ${page.title}`,
    page.publishedAt ? `*公開日時*: ${formatJST(page.publishedAt, conf.TZ)}` : "",
    page.url ? `*リンク*: ${page.url}` : "",
  ].filter(Boolean);


  const payload = { text: lines.join("\n") };


  const res = UrlFetchApp.fetch(conf.SLACK_WEBHOOK_URL, {
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  });
  const code = res.getResponseCode();
  if (code >= 300) throw new Error(`Slack Webhook error: ${code} / ${res.getContentText()}`);
}


function formatJST(iso, tz) {
  return Utilities.formatDate(new Date(iso), tz, "yyyy/MM/dd HH:mm");
}


function assertRequired(conf) {
  const miss = [];
  if (!conf.NOTION_TOKEN) miss.push("NOTION_TOKEN");
  if (!conf.NOTION_DATABASE_ID) miss.push("NOTION_DATABASE_ID");
  if (!conf.SLACK_WEBHOOK_URL) miss.push("SLACK_WEBHOOK_URL");
  if (miss.length) throw new Error("スクリプトプロパティ未設定: " + miss.join(", "));
}


// ===== 手動テスト用(任意)=====
// 実行:メニューから run → testOnce
function testOnce() {
  const conf = CONF();
  SP().deleteProperty("LAST_CHECKED_AT"); // ← 最終チェック時刻を消す
  SP().deleteProperty("NOTIFIED_MAP");    // ← 通知済みリストを消す(ここがリセット)
  SP().setProperty("DRY_RUN", "false");   // 本番モード
  pollNotionAndNotify();
}




function resetNotifiedMap() {
  SP().deleteProperty("NOTIFIED_MAP");
  SP().deleteProperty("LAST_CHECKED_AT");
  console.log("通知履歴をリセットしました。");
}

5. 権限付与と最初のテスト

ここまでくればあとは実行するだけです。テストをして通知が飛ぶことを確認してください。

エディタ上部の関数プルダウンで testOnce を選び、▶ 実行

初回は権限ダイアログが出るので、Googleアカウントにログインして許可

実行ログ(表示 → 実行ログ)にエラーがないことを確認

Notion側でテスト用記事を作成し、ステータス=「公開」、公開日時=現在時刻
に変更 → testOnce を再実行

ログにその記事が表示されればOK

DRY_RUNで問題なければ、スクリプトプロパティの DRY_RUN をfalse にして、
再度 testOnce を実行 → Slackに実際の通知が飛ぶことを確認。

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

左側サイドバーの 時計アイコン(トリガー) を開く

トリガーを追加
実行する関数:pollNotionAndNotify
イベントのソース:時間主導型
時間ベースのトリガー:分ベースのタイマー
間隔:5分 など
保存

以後、5分おきに「公開+公開日時が前回以降」の記事だけ通知します。
二重通知はスクリプトプロパティの NOTIFIED_MAP が防ぎます。

よくある質問

プログラミング未経験でも導入できますか?

はい。記事内のコードをそのままコピー&ペーストして設定すれば動作します。つまずきやすい部分(DB共有やプロパティ名)は本文で注意点を解説しています。

通知内容をカスタマイズできますか?

可能です。Slack通知文に記事タイトル・公開日時・URLを含めるだけでなく、メンションや絵文字を加えることもできます。

誤って同じ記事が何度も通知されませんか?

いいえ。スクリプト内で「通知済み記事ID」を記録しているため、同じ記事が再度通知されることはありません。

外部公開していない記事も通知できますか?

はい。Notionのステータスを「公開」にしたタイミングで通知する仕組みなので、外部公開とは連動していなくても通知が可能です。

新規記事の自動社内Slack通知がなかなかうまくいかないときは?

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

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

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

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

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

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

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

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

まとめ

NotionとSlackを連携し、記事公開を自動通知できるようにすれば、情報共有のスピードと正確さが大幅に向上します。最初の設定こそ少し手間がかかりますが、一度導入すれば毎回の手作業から解放され、通知漏れも防げます。特に、複数人で記事を管理しているチームや、公開と同時に社内アナウンスが必要な場面では大きな効果を発揮します。無料で始められる仕組みなので、ぜひ一度導入してみてください。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ジドウカとは?

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

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

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

ジドウカが選ばれる理由

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