New to Kestra?
Use blueprints to kickstart your first workflows.
React to Notion page changes in real time, alert Slack on bulk-edit anomalies, and log the result for compliance and docs teams.
Diagram unavailable
We could not build the topology for this blueprint. The flow itself is valid, use the YAML on the left to run it.
A policy, runbook, or pricing page that changes without anyone announcing it is easy to miss; Notion's own page history shows who edited what only if someone thinks to check. This blueprint watches a monitored parent page's children continuously and treats a sudden burst of simultaneous edits, the kind an automation bug or a compromised integration token could cause, differently from one person making a routine update.
This blueprint was created by Mohit Jeswani.
watch_monitored_pages (io.kestra.plugin.notion.page.UpdateTrigger) polls Notion's
Search API every 5 minutes, scoped to direct children of parentPageId, and fires one
execution per poll that found at least one changed page.evaluate (io.kestra.plugin.core.output.OutputValues) counts the changed pages in this
one poll with a jq filter and classifies a count at or above
max_routine_change_count as BULK_EDIT_ANOMALY, otherwise PAGE_CHANGED.route (io.kestra.plugin.core.flow.If):summary logs the change count and severity for every poll, closing the governance
cycle.errors alerts Slack if the flow itself fails, for example an expired API token.page.UpdateTrigger used
as a standing change-audit sentinel, distinct from this repo's other Notion blueprints,
which create or update pages and query a database rather than watching for changes in
real time.Notion's own page history shows every edit one page at a time; it does not watch a whole
page tree, compare the change rate against what you consider routine, or notify a Slack
channel when a burst looks anomalous. Kestra keeps max_routine_change_count as a flow
input, turns a bulk-edit burst into a Slack page naming the real pages involved, and keeps a
full execution history of every poll that found a change.
This flow calls the Notion API directly over HTTPS; there is no official local Notion
emulator, so watch_monitored_pages cannot be exercised against a local Docker container.
NOTION_API_TOKEN: the Notion internal integration token used by watch_monitored_pages.
In Kestra OSS, provide it as the base64-encoded environment variable
SECRET_NOTION_API_TOKEN.SLACK_WEBHOOK_URL: used by alert and the errors block. In Kestra OSS, provide it as
the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.| Input | Default | Purpose |
|---|---|---|
max_routine_change_count |
5 |
Pages-changed-per-poll count at or above which the batch is classified as a bulk-edit anomaly |
{{ trigger.updatedPages }}: the changed pages this poll found (pageId, url, title,
lastEditedTime), as UpdateTrigger reports them.{{ outputs.evaluate.values.updated_count }} / .updated_summary: how many pages changed
and their titles (or URL/ID when a title cannot be resolved), semicolon-joined.{{ outputs.evaluate.values.severity }}: PAGE_CHANGED or BULK_EDIT_ANOMALY.parentPageId filtering happens client-side after Notion's Search API call, since the
Search API has no server-side parent filter; a page tree with very high edit volume can
mean more API calls per poll than the matched-page count alone suggests.last_edited_time has only minute-level precision in Notion's API; two edits inside the
same minute as a previous poll's watermark are both still caught, but cannot be
distinguished from each other by timestamp alone.inputs: to override per execution, since a polling trigger's own
configuration (parentPageId, interval) is set directly on the trigger block, not
templated from flow inputs.NOTION_API_TOKEN and SLACK_WEBHOOK_URL secrets, and share the target parent
page with your Notion integration.parentPageId on watch_monitored_pages to a real parent page's ID.routine_log fires.max_routine_change_count or more child pages within one 5-minute poll window to
confirm alert fires as BULK_EDIT_ANOMALY.query to watch_monitored_pages to scope the watch to pages matching a keyword,
narrowing the search server-side instead of relying on parentPageId alone.io.kestra.plugin.notion.page.Read on each changed page to pull its full content
into the alert, not just the title and link.updated_count over successive polls in a KV entry to chart edit-burst frequency
over time, not just flag the current poll.