NocoDB Database Platform Health, Storage Engine, and Project Sentinel
Continuous health, SQL storage backend, and project metadata monitoring for NocoDB no-code database platforms.
React to Notion page changes in real time, alert Slack on bulk-edit anomalies, and log the result for compliance and docs teams.
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.