Notion has become the default workspace for thousands of teams — but its real power unlocks when you connect it to the rest of your stack. The n8n Notion node lets you read and write Notion databases, create and update pages, manage blocks, and trigger workflows from Notion events. This guide covers the operations you'll use most, the gotchas that trip up new users, and three production patterns that actually ship.
Prerequisites
- n8n (self-hosted or cloud)
- A Notion account with at least one database
- A Notion integration (internal or public) with the right capabilities
Setting up the Notion integration:
- Go to notion.so/my-integrations → New integration
- Give it a name, select your workspace, set capabilities: Read content, Update content, Insert content
- Copy the Internal Integration Secret
- In your Notion database/page: ⋯ menu → Add connections → your integration name (Notion requires explicit page-level connection grants)
In n8n: Credentials → New → Notion API → paste your Internal Integration Secret.
Operations at a Glance
| Operation | What It Does |
|---|---|
| Database: Get | Fetch database metadata (schema, properties) |
| Database: Get Many | List databases the integration has access to |
| Database: Query | Filter and sort records in a database |
| Page: Create | Add a new page/row to a database |
| Page: Get | Fetch a page by its ID |
| Page: Update | Update page properties |
| Page: Archive | Archive (soft-delete) a page |
| Block: Get Many | Read the content blocks of a page |
| Block: Append | Add new blocks to a page |
Key Configuration Concepts
Finding Your Database ID
Your Notion database URL looks like:
https://www.notion.so/myworkspace/abc123def456...?v=...
The database ID is the alphanumeric string between the last / and the ?v=. In n8n, you can paste the full URL — the node parses it automatically.
Property Types Matter
Notion properties have types (title, rich_text, number, select, multi_select, date, checkbox, url, email, phone_number, relation, formula, rollup). The n8n Notion node exposes these as typed fields. A common error: trying to set a formula or rollup field — those are computed by Notion, not writable via API.
Filtering in Database: Query
Filters use Notion's compound filter syntax. In n8n's UI, you build these with the visual filter builder. For complex compound filters, use the JSON input mode:
{
"and": [
{ "property": "Status", "select": { "equals": "Active" } },
{ "property": "MRR", "number": { "greater_than": 100 } }
]
}
3 Production Workflow Patterns
Pattern 1: CRM-to-Notion Database Sync
Use case: New leads come in from a Typeform or webhook. You want them in a Notion CRM database — deduplicated, enriched, and linked to the right company page.
Workflow:
- Webhook Trigger — receives lead data (name, email, company, source).
-
Notion – Database: Query — filter:
{ "property": "Email", "email": { "equals": "{{ $json.email }}" } }. Returns existing record if the lead exists. -
IF node —
{{ $json.results.length > 0 }}→ true (existing) or false (new).- False branch (new lead): Notion – Page: Create — database ID: your CRM DB, properties: name (title), email, company, source, Status (select: "New"), Created (date: today).
-
True branch (existing lead): Notion – Page: Update — page ID from query results, update
Last Seendate and append toNotes.
- Merge node — rejoin and send a Slack notification either way.
Key config on Page: Create:
- Properties → Title → set to lead name
- Use the "Additional Fields" section for non-title properties
- Date fields require ISO 8601 format:
{{ $now.toISO() }}
Pattern 2: Automated Weekly KPI Report to Notion
Use case: Every Monday morning, pull KPI data from Stripe (revenue, new customers, refunds) and write it to a Notion database as a new weekly report page — so the team has a running log of weekly metrics in Notion without manual copy-paste.
Workflow:
- Schedule Trigger — every Monday at 8:00 AM.
-
HTTP Request node — Stripe API:
GET /v1/charges?created[gte]={{ $now.startOf('week').subtract(1, 'week').toUnixInteger() }}&created[lte]={{ $now.startOf('week').toUnixInteger() }}to get last week's charges. - Code node — aggregate: sum amounts, count customers, sum refunds, compute net revenue.
-
Notion – Page: Create — in your KPI Reports database:
- Title:
Week of {{ $now.startOf('week').subtract(1, 'week').toFormat('MMM d') }} - MRR (number): net revenue
- New Customers (number): customer count
- Refunds (number): refund total
- Status (select): "Published"
- Title:
- Notion – Block: Append — append a rich text block to the new page with a formatted summary paragraph.
- Slack node — notify #metrics channel with the Notion page URL.
Gotcha: Notion page IDs from Page: Create are returned in the response as id. Use {{ $json.id }} in Block: Append to reference the just-created page.
Pattern 3: Notion-Triggered Fulfillment Workflow
Use case: Your team manages client project approvals in Notion. When a project page's Status property changes to "Approved", automatically send the client a welcome email, create a Trello card for the team, and update a Google Sheet.
Notion doesn't support real-time webhooks natively — you'll poll with the Schedule Trigger and check for recently-updated records.
Workflow:
- Schedule Trigger — every 5 minutes.
-
Notion – Database: Query — filter for pages where
Status = "Approved"ANDLast Edited Timeis after your last-check timestamp (store this in a Set node or a simple n8n static variable). - IF node — skip if results are empty.
- Split In Batches node — process each newly-approved project one at a time.
-
Resend node — send welcome email to
{{ $json.properties.Client_Email.email }}. - HTTP Request node — Trello API: create a card in the "Active Projects" list.
- Google Sheets node — append a row to the project tracker sheet.
-
Notion – Page: Update — set
Automation_Sentcheckbox totrueso re-runs skip this record.
Key config: The Automation_Sent checkbox flag is the dedup mechanism. Without it, every poll cycle re-processes all "Approved" records.
6 Common Gotchas
1. You must connect the integration to each page/database explicitly
Even if your integration has the right capabilities, Notion requires you to manually share each database or page with the integration via ⋯ → Add connections. "Not found" errors are almost always this. Fix: share the database with your integration in Notion's UI.
2. Title property is always required for Page: Create
Every Notion page has exactly one title property. You must set it — its name varies by database (could be "Name", "Title", "Task", etc.). Map it under the title input, not as an additional field.
3. Rich text values are arrays of text objects, not plain strings
When reading page content, rich text properties return [{ "plain_text": "...", "annotations": {...} }]. To get the plain string value: {{ $json.properties.Notes.rich_text[0].plain_text }}. For multi-block rich text: map and join.
4. Formula and rollup fields are read-only
You can read computed values from formula/rollup fields, but writing to them throws an error. Only update fields whose source data lives in that page.
5. Notion rate limits: 3 requests/second per integration
Loops over large databases will hit rate limits quickly. Add a Wait node (400ms) between iterations, or use Database: Query pagination (page_size max 100) and the has_more / next_cursor response fields to paginate manually.
6. Archived pages don't appear in Database: Query by default
If a page was archived, it won't show up in query results (Notion excludes archived records). To fetch archived pages, you need to hit the Search endpoint directly via HTTP Request. For most use cases, just make sure you're not accidentally archiving records you still need.
Free Workflow JSON
This implements Pattern 1 (Webhook → Notion CRM sync with dedup). Import via n8n → Import from JSON.
{
"name": "Webhook → Notion CRM Sync (Dedup)",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "notion-crm-intake",
"responseMode": "responseNode"
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"operation": "query",
"databaseId": "YOUR_NOTION_DATABASE_ID",
"filterJson": "={ \"property\": \"Email\", \"email\": { \"equals\": \"{{ $json.body.email }}\" } }"
},
"name": "Search Existing Lead",
"type": "n8n-nodes-base.notion",
"typeVersion": 2,
"position": [460, 300]
},
{
"parameters": {
"conditions": {
"number": [{ "value1": "={{ $json.results.length }}", "operation": "larger", "value2": 0 }]
}
},
"name": "Lead Exists?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [680, 300]
},
{
"parameters": {
"operation": "create",
"databaseId": "YOUR_NOTION_DATABASE_ID",
"title": "={{ $('Webhook').item.json.body.name }}",
"propertiesUi": {
"propertyValues": [
{ "key": "Email", "emailValue": "={{ $('Webhook').item.json.body.email }}" },
{ "key": "Company", "textValue": "={{ $('Webhook').item.json.body.company }}" },
{ "key": "Status", "selectValue": "New" }
]
}
},
"name": "Create New Lead",
"type": "n8n-nodes-base.notion",
"typeVersion": 2,
"position": [900, 400]
},
{
"parameters": {
"operation": "update",
"pageId": "={{ $json.results[0].id }}",
"propertiesUi": {
"propertyValues": [
{ "key": "Last Seen", "dateValue": "={{ $now.toISO() }}" }
]
}
},
"name": "Update Last Seen",
"type": "n8n-nodes-base.notion",
"typeVersion": 2,
"position": [900, 200]
}
],
"connections": {
"Webhook": { "main": [[{ "node": "Search Existing Lead", "type": "main", "index": 0 }]] },
"Search Existing Lead": { "main": [[{ "node": "Lead Exists?", "type": "main", "index": 0 }]] },
"Lead Exists?": {
"main": [
[{ "node": "Update Last Seen", "type": "main", "index": 0 }],
[{ "node": "Create New Lead", "type": "main", "index": 0 }]
]
}
}
}
Replace YOUR_NOTION_DATABASE_ID with your database ID and configure your Notion API credential.
Wrapping Up
The n8n Notion node covers the full database lifecycle — querying, creating, updating, and archiving pages. The patterns with the highest leverage are the sync patterns: pulling data from other systems into Notion as a structured record store, and using Notion as a lightweight approval layer that triggers downstream automation. The gotcha that bites most new users: sharing the integration with each database in Notion's UI — "not found" errors are almost always a missing connection grant, not a credential problem.
Want the full n8n Workflow Starter Pack? 25+ production-ready workflow templates covering lead capture, Stripe automation, AI pipelines, and more — $29 on Gumroad.
Need a custom n8n workflow built for your business? Done-for-you service — $99. Describe your automation, get a working workflow delivered.
Top comments (1)
Are you using the Notion node to sync CRM records, generate weekly KPI reports, or trigger fulfillment from a Notion database? Drop your use case in the comments — always curious what people are building with Notion + n8n.