こんにちは。ソーシャル経済メディア「NewsPicks」のプラットフォームエンジニアリングチームの韓です。
普段の業務では主にNewsPicksの動画配信サービスや課金基盤システムの開発・運用を行っています。
今回はNotion APIとZapierを使って、NewsPicksの動画制作を担当しているNewsPicks Studiosの業務DXを推進した事例をご紹介します。 Notionを活用した事業部の業務DXや、Notion API・Zapier を用いたデータ連携に興味のある方は、ぜひご一読ください。
はじめに
なぜ Notionで業務DXを進めたのか
NewsPicksではNotionを全社導入しています。全社で情報をNotionに集約することを推奨していたため、事業部の情報をまとめる媒体としても最適でした。 また、Integration機能が充実していて、さまざまなシステムとの連携が容易に行える点も、Notion を選んだ大きな理由の一つです。
従来の業務データ管理の課題
データソースや管理ツールが担当業務ごとにバラバラで、管理が煩雑になっていました。
Slack上で案件相談を通して情報を共有していましたが、担当業務間で個別に情報を管理していたため、情報の共有に多くのコミュニケーションコストがかかっていました。
また、担当業務ごとにデータソースが分散していたため、部署を横断したデータ活用の観点でも課題がありました。
Notion APIとZapierを選んだ理由
データ連携にNotion APIとZapier選択した理由は大きく以下の2点です。
ノーコードツールを利用し、なるべく少ない開発工数で成果を出したかった。
Zapierでは補えない要件に対応するため、一部をNotion APIによるデータ連携で補完したかった。
設計
設計の全体像
SalesforceのデータはZapierで、社内システムのデータはNotion APIで連携しました。
当初はGoogle Spreadsheetとの連携をApp Scriptで行う予定でしたが、最終的には Notion にデータを集約する方針に変更。Spreadsheetの運用は廃止し、必要なデータは直接Notionに入力してもらう形にしました。
Notionデータベースの設計

Notionデータベースは、Salesforceから連携するデータベースを親とし、その他の社内システムからのデータベースを連携。それらをSalesforceの商談 IDをキーにリレーションを作成して、一つのデータベースに集約する形で設計しました。
実装
Salesforce -> NotionのZap作成
Salesforceの更新トリガーを作成
AppにSalesforceを選択し、トリガーイベントにUpdated Record を選択。
Salesforceのレコード更新をトリガーにZapierを発火させるための設定です。

商談単位でオブジェクトを取得するためSalesforce Objectの設定は商談を指定します。

フィルターステップを追加
営業担当者や広告主が入力されているかどうかでレコードを振り分けるため、フィルターの工程をはさみます。
EventはFind Recordを選択し、Search ValueにSalesforce上で営業担当者に当たる項目を設定します。

Notionデータベースの更新
Salesforceから取得したデータがすでにNotionデータベース上に存在するかを確認するステップを追加します。

Notionデータベースの更新
最後にUpdate Database Itemを指定してNotionデータベースにデータを連携します。
Zapの設定はこれで終わりです。

Zapの全体像
最終的なZapの全体像です。
Pathsでは営業担当、広告主が設定されているかどうかのConditionを設定しています。
これでSalesforceのレコード更新をトリガーにNotionデータベースにSalesforceのデータを連携することができるようになります。

社内システム -> Notionのデータ連携
Notion APIによるデータ連携

社内システムからNotionへの動画データの連携はNotion APIを使っています。
動画データは「動画管理」のデータベースに連携し、「案件管理」のデータベースとのリレーションを作成することで、ロールアップで表示できるようにします。
必要なNotion API設定・認証のポイント
Notion APIでデータベースを更新するためにはインテグレーションの作成とデータベースの接続設定が必要です。
https://www.notion.so/profile/integrations/form/new-integration からインテグレーションを作成します。

データベース > 接続から作成したインテグレーションの接続を設定します。
これでNotion APIで対象のデータベースを操作することができるようになります。

Notion APIの実装
Notion APIで現時点でサポートされているSDKはJavaScriptのみということと、社内のシステムがKotlinで実装されていることからNotion APIの実行はSDKを使わずKotlinで実装しました。
Notion APIはIntegration Keyを設定してRetrofitでREST APIを実行する形で実装しました。
(後になって考えてみると、この程度であればインターフェースを作らずJSONを投げるだけのシンプルな実装でも良かったかもしれません)
// Notion APIのインターフェース @Retry(count = 3) interface NotionClient { @POST("/v1/databases/{databaseId}/query") fun queryDatabase( @Header("Authorization") token: String, @Header("Notion-Version") version: String = "2022-06-28", @Header("Content-Type") contentType: String = "application/json", @Path("databaseId") databaseId: String, @Body request: NotionQueryDatabaseRequest, ): Try<NotionQueryDatabaseResponse> @POST("/v1/pages") fun createPage( @Header("Authorization") token: String, @Header("Notion-Version") version: String = "2022-06-28", @Header("Content-Type") contentType: String = "application/json", @Body request: NotionCreatePageRequest, ): Try<NotionCreatePageResponse> @PATCH("/v1/pages/{pageId}") fun updatePage( @Header("Authorization") token: String, @Header("Notion-Version") version: String = "2022-06-28", @Header("Content-Type") contentType: String = "application/json", @Path("pageId") pageId: String, @Body request: NotionUpdatePageRequest, ): Try<NotionUpdatePageResponse> @PATCH("/v1/pages/{pageId}") fun trashPage( @Header("Authorization") token: String, @Header("Notion-Version") version: String = "2022-06-28", @Header("Content-Type") contentType: String = "application/json", @Path("pageId") pageId: String, @Body request: NotionTrashPageRequest, ): Try<NotionTrashPageResponse> } // Notionと社内システムの同期処理 fun syncronizeMovieWithNotion(movieId: MovieId) { val movie = movieService.getMovie(movieId) // Notion APIのIntegrationKeyとデータベース設定を取得 val token = notionService.getNotionToken() val config = notionService.getNotionConfig() val notionPage = notionService.queryNotionDatabase(token, config.databaseId, movieId) // 動画が削除済みの場合は関連pageを削除 if (movie == null) { notionPage?.let { notionService.trashPage(token, notionPage.id) } return } if (notionPage != null) { // SFDC_IDが設定されていない場合はページをアーカイブ if (movie.salesForceId.isNullOrEmpty()) { notionService.trashPage(token, notionPage.id) return } // ページの更新 val sfdcPage = notionService.querySfdcDatabase(token, config, movie) ?: return notionService.updatePageProperties(token, config, moviePage.id, sfdcPage, liveMovie) } else { // ページの新規作成 if (!!movie.salesId.isNullOrEmpty()) { val sfdcPage = notionService.queryNpsSfdcDatabase(token, config, movie) ?: return notionService.createPage(token, config, sfdcPage, movie) } } }
リレーションとロールアップの設定
「案件管理」のデータベースと「動画管理」のデータベースのリレーションを作成します。

リレーションを作成後、「案件管理」のデータベースに表示したい項目を「動画管理」のデータベースからロールアップで統合します。
これで「案件管理」のデータベース上に「動画管理」の項目も表示されるようになりました。

成果物
最終的にSalesforce と社内システムのデータが Notion データベースに自動連携され、営業・企画・プロデューサーが 同じデータソース を見ながら業務を進められるようになりました。
Notionに集約することで、ビューやフィルターを活用し、利用者ごとに最適化された表示を柔軟に提供できるようになりました。
事業部の方々からも業務が進めやすくなったという声をいただけたので一定の成果は出せたのではないかと思います。
まとめ
今回ご紹介したように、Notion APIとZapierを活用することで、従来はバラバラに管理されていたデータやシステムを一元化し、業務効率を大きく改善することができました。
今回のNotionを使ったDXのポイントを振り返ると、次の 3 点に集約されます。
ノーコードツールを最大限に活用し、少ない工数で成果を出す。
ノーコードで実現できない部分をAPI連携で補完する。
Notionにデータを集約することで、関係者全員が同じデータを参照できる状態を実現できる。
この仕組みにより、営業・企画・プロデューサーといった立場の異なるメンバーが同じ情報を共有しながら、よりスムーズに業務を進められるようになりました。
今後もさらなる改善を積み重ねて、事業部のDXを推進していきたいと考えています。
今回の事例が、NotionやZapierを使った業務フロー改善を検討されている方の参考になれば幸いです。