Notionで書いた記事を Githubに連携 → Zenn/Qiita/個人ブログに自動投稿する
概要
エンジニアとして日々勉強したことを楽にアウトプットできたらいいなと思い、
Notionで作った記事を、ワンクリックで Githubに同期 → Zenn/Qiita/個人ブログにも公開できる仕組みを作ってみました!
ステップ1:環境の準備
このステップで準備する要素
📌 今ここ: Notion、GitHub、公開プラットフォームの準備
Notion記事管理データベースの作成
-
記事の公開状態を管理する、「WIP」「Preview」「Published」のステータスカラムを用意します
-
例: こんな感じのデータベースに記事をつくっていき、「Status」カラムで公開ステータスを変更していくイメージです

GitHubリポジトリの作成
- Notionの記事をNotion APIで同期して、マークダウンとしておいておくGitHubリポジトリを作成します
- 例: https://github.com/majikana-rinadehi/document-hub
公開プラットフォームのアカウント準備
- ZennやQiita、個人ブログなど、最終的に記事投稿したいプラットフォームのアカウントを用意しておきます
ステップ2:Notionインテグレーションの作成
📍 このセクションの位置(全体フロー)
📌 今ここ: Notion API経由でデータを取得するための認証設定を行います
まず、GitHubからNotionのデータにアクセスするために、Notionインテグレーションを作成します。
Notion統合の作成とAPIトークン取得
- 手順
- Notion統合ページにアクセスします
- 「新しいインテグレーション」→ Typeは「内部インテグレーション」(Internal)を選択して、インテグレーションを新規作成します
- 内部インテグレーションシークレットが表示されているので、後でGithub Actions側に設定するために値をコピーしておきます
データベースとの接続設定
作成した統合を記事管理用データベースに接続します。
- 手順
- 統合管理ページで作成した統合を選択します
- 「Access」タブから「Select page access」で、先ほど作った記事管理用データベースを選択します
- Notionの記事管理用データベースページの右上「…」→「Connections」に統合が追加されることを確認します
ステップ3:Notion ⇔ GitHub の連携
📍 このセクションの位置(全体フロー)
📌 今ここ: NotionとGitHubを連携して、記事更新時にWebhook経由でGitHub Actionsをキックする仕組みを作ります
3.1 プロキシサーバーの用意
NotionのWebhookからGitHub Actionsを起動するには、GitHubの認証情報をヘッダーに含める必要があります。そこで、Notion → GitHub の間に Vercel Function でプロキシサーバーを挟んで、認証情報を追加してからGitHubに転送するようにします。
実装
proxy/api/ 配下に下記のようなエンドポイントを作って vercel コマンドでデプロイします。
proxy/api/webhooks.js
import { Octokit } from "@octokit/rest";
export default async function handler(req, res) {
// CORSヘッダー設定
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
// OPTIONSリクエスト対応
if (req.method === "OPTIONS") {
return res.status(200).end();
}
// POSTリクエストのみ許可
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
try {
console.log("=== Notion Webhook Received ===");
console.log("Headers:", req.headers);
console.log("Body:", req.body);
// GitHub APIクライアント初期化
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
// NOTE: No more than 10 properties are allowed; 12 were supplied.
const clientPayload = { ...req.body };
// client_payloadのプロパティ数を10に制限
// 次は必ず含む: id, timestamp, data, type, entity, authors, integration_id, subscription_id, workspace_name, workspace_id
const allowedKeys = [
"id",
"timestamp",
"data",
"type",
"entity",
"authors",
"integration_id",
"subscription_id",
"workspace_name",
"workspace_id",
];
Object.keys(clientPayload).forEach((key) => {
if (!allowedKeys.includes(key)) {
delete clientPayload[key];
}
});
// repository_dispatch実行
await octokit.rest.repos.createDispatchEvent({
owner: process.env.GITHUB_OWNER,
repo: process.env.GITHUB_REPO,
event_type: "notion-article-updated",
client_payload: {
...clientPayload,
},
});
console.log("GitHub Actions triggered successfully");
return res.status(200).json({
success: true,
message: "Webhook processed successfully",
});
} catch (error) {
console.error("Error processing webhook:", error);
return res.status(500).json({
success: false,
error: error.message,
});
}
}
注意点
- ⚠️ Vercel認証の無効化
- Vercelの「Project Settings」→「Deployment Protection」→「Vercel Authentication」をOFFにしておきましょう。これをやらないとWebhookリクエストで401エラーになります。
- ⚠️ client_payloadの制限
- GitHub Actionsの
client_payloadは10個までしかプロパティを渡せないので、必要最小限のプロパティに絞ってます。
- GitHub Actionsの
3.2 [Notion] Webhookの設定
Notion側の記事更新時にGitHub Actionsを起動させたいので、インテグレーションに Notion Webhook を設定します。
Webhook URL
プロキシサーバーのURLを指定します。
https://xxx.vercel.app/api/webhooks
※ 初回の認証でこのエンドポイントに認証情報が送られてくるので、Vercel Functionsのログで確認できます。
Subscribed events
「Page properties updated」を選択します。
これで、Notion側で記事の Status カラムが変更されたときにWebhookが発火して、GitHub Actionsがトリガーされます。
3.3 [GitHub] Personal Access Token (PAT)の設定
GitHub ActionsのAPIを呼び出すために必要なPATを生成します。詳細は GitHub API ドキュメント を参照してください。
このPATの値は Vercel Functions の環境変数 GITHUB_TOKEN に設定して、ヘッダーに含めて認証情報としてGitHub Actionsに送ります。
- 必要な権限
-
repo(リポジトリへのフルアクセス) -
workflow(GitHub Actionsワークフローの実行)
-
ステップ4:GitHub側の準備
Actionsの用意
-
.github/workflows/配下に、下記のようなトリガーでActionsを新規作成・実装していきます
publish-to-zenn.yml
例: Zenn用のワークフロー設定
name: Publish to Zenn
on:
repository_dispatch:
types: [notion-article-updated]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Fetch from Notion
env:
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
run: node scripts/fetch-notion.js
- name: Convert to Markdown
run: node scripts/convert-markdown.js
- name: Deploy to Zenn
run: |
cp -r output/articles ./articles
cp -r output/images ./images
変換スクリプトの実装
GitHub Actionsに、下記のスクリプトを組み込んでいきます
- Notionページ情報の取得
- Markdown変換処理
Zenn連携
記事にZennタグが付けられている場合、Zennにもデプロイします。
- Zenn CLIを使用してデプロイします
- outputの内容を
{articles|images}にコピーします
Zennメタデータの設定
[TODO] Qiita / 個人ブログ
→同じように、Qiita API や個人ブログのデプロイ設定を追加していきます
ステップ4:テスト
📍 このセクションの位置(全体フロー)
📌 今ここ: 全体の実装が完了したので、実際に動作するかテストします
テスト方法
ここでは、Notionで記事のステータスを変更して、実際にGitHub経由でZennなどに記事が公開されるかを確認します。
テスト用記事の準備
まずはテスト用の記事を作成しましょう。
- Notionの記事管理データベースで新しいページを作成
- タイトルと本文を簡単に書く(テスト用なので「これはテスト記事です」程度でOK)
- 「Platforms」カラムで「Zenn」を選択
- 「Status」カラムを「WIP」に設定
実際にテストしてみる
記事の準備ができたら、実際に公開フローを動かしてみます。
- ステータスを「Preview」に変更
- GitHub Actionsの実行を確認
- リポジトリの更新を確認
- Zenn での公開を確認
成功の確認方法
テストが成功しているかは、以下のポイントでチェックできます。
- ✅ Webhook が正常に動作しているか
- Vercel Functions のログに Webhook リクエストが記録されている
- ログに
GitHub Actions triggered successfullyが出力されている
- ✅ GitHub Actions が正常に実行されているか
- GitHub の Actions タブでワークフローが緑色(成功)になっている
- ワークフローの各ステップが完了している
- ✅ 記事が正しく公開されているか
- Zenn/Qiita の管理画面で記事が表示されている
- 画像が正しく表示されている
- フォーマットが崩れていない
- メタデータ(タグ、カテゴリなど)が正しく設定されている
これでテストは完了です!うまく動いたら、実際の記事で運用を始めましょう 🎉
まとめ
Notionでドキュメントを管理でき、数クリックでGIt連携・記事公開までできるので、
アウトプットへのハードルが下がったと感じています!
今後もこの仕組みでどんどんアウトプットしていこうと思っています!
Discussion