notion
Notion Integration
Connect your Notion workspace to OpenClaw for seamless knowledge management and project tracking.
When to Use This Skill
Use Notion when the user wants to:
- Add items to a database (backlog, todos, tracking)
- Create new pages in a database or as children of existing pages
- Query/search their Notion workspace for information
- Update existing pages (status, notes, properties)
- Read page content or database entries
Setup
1. Create Notion Integration
- Go to notion.so/my-integrations
- Click New integration
- Name it (e.g., "OpenClaw")
- Select your workspace
- Copy the Internal Integration Token (starts with
secret_) - Save this token securely in OpenClaw config or environment:
NOTION_TOKEN=secret_...
2. Share Pages with Integration
Important: Notion integrations have NO access by default. You must explicitly share:
- Go to any page or database in Notion
- Click Share → Add connections
- Select your "OpenClaw" integration
- The skill can now read/write to that specific page/database
3. Get Database/Page IDs
From URL:
- Database:
https://www.notion.so/workspace/XXXXXXXX?v=...→ ID isXXXXXXXX(32 chars) - Page:
https://www.notion.so/workspace/XXXXXXXX→ ID isXXXXXXXX
Note: Remove hyphens when using IDs. Use the 32-character string.
Core Operations
Query Database
Retrieve entries from any database you've shared.
// Using the Notion skill via exec
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js query-database ${databaseId}`
});
// With filters (example: status = "In Progress")
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js query-database ${databaseId} --filter '{"property":"Status","select":{"equals":"In Progress"}}'`
});
Returns: Array of pages with properties as configured in your database.
Add Database Entry
Create a new row in a database.
// Add entry with multiple properties
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js add-entry ${databaseId} \
--title "My New Content Idea" \
--properties '${JSON.stringify({
"Status": { "select": { "name": "Idea" } },
"Platform": { "multi_select": [{ "name": "X/Twitter" }] },
"Tags": { "multi_select": [{ "name": "3D Printing" }, { "name": "AI" }] },
"Priority": { "select": { "name": "High" } }
})}'`
});
Get Page Content
Read the content of any page (including database entries).
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js get-page ${pageId}`
});
Returns: Page title, properties, and block content (text, headings, lists, etc.).
Update Page
Modify properties or append content to an existing page.
// Update properties
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js update-page ${pageId} \
--properties '${JSON.stringify({
"Status": { "select": { "name": "In Progress" } }
})}'`
});
// Append content blocks
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js append-body ${pageId} \
--text "Research Notes" --type h2`
});
Search Notion
Find pages across your shared workspace.
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js search "content ideas"`
});
Common Use Cases
Content Pipeline (Content Creator Workflow)
Database Structure:
- Title (title)
- Status (select: Idea → Draft → Scheduled → Posted)
- Platform (multi_select: X/Twitter, YouTube, MakerWorld, Blog)
- Publish Date (date)
- Tags (multi_select)
- Draft Content (rich_text)
OpenClaw Integration:
// Research scout adds findings to Notion
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js add-entry ${contentDbId} \
--title "New 3D Print Technique" \
--properties '${JSON.stringify({
"Status": { "select": { "name": "Idea" } },
"Platform": { "multi_select": [{ "name": "YouTube" }] },
"Tags": { "multi_select": [{ "name": "3D Printing" }] }
})}'`
});
// Later: Update when drafting
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js update-page ${entryId} \
--properties '${JSON.stringify({
"Status": { "select": { "name": "Draft" } },
"Draft Content": { "rich_text": [{ "text": { "content": "Draft text here..." } }] }
})}'`
});
Project Management (Solo Entrepreneur)
Database Structure:
- Name (title)
- Status (select: Not Started → In Progress → Blocked → Done)
- Priority (select: Low → Medium → High → Critical)
- Due Date (date)
- Estimated Hours (number)
- Actual Hours (number)
- Links (url)
- Notes (rich_text)
Weekly Review Integration:
// Query all "In Progress" projects
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js query-database ${projectsDbId} --filter '{"property":"Status","select":{"equals":"In Progress"}}'`
});
Customer/Quote CRM (3D Printing Business)
Database Structure:
- Customer Name (title)
- Status (select: Lead → Quote Sent → Ordered → Printing → Shipped)
- Email (email)
- Quote Value (number)
- Filament Type (select)
- Due Date (date)
- Shopify Order ID (rich_text)
Shopify Integration:
// New order → create CRM entry
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js add-entry ${crmDbId} \
--title "${customerName}" \
--properties '${JSON.stringify({
"Status": { "select": { "name": "Ordered" } },
"Email": { "email": customerEmail },
"Shopify Order ID": { "rich_text": [{ "text": { "content": orderId } }] }
})}'`
});
Knowledge Base (Wiki Replacement for MEMORY.md)
Structure: Hub page with nested pages:
- 🏠 Home (shared with integration)
- SOPs
- Troubleshooting
- Design Patterns
- Resource Links
Query for quick reference:
// Search for "stringing" to find 3D print troubleshooting
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js search "stringing"`
});
Property Types Reference
When creating/updating database entries, use these property value formats:
// Title (always required for new pages)
{ "title": [{ "text": { "content": "Page Title" } }] }
// Select (single choice)
{ "select": { "name": "Option Name" } }
// Multi-select (multiple choices)
{ "multi_select": [{ "name": "Tag 1" }, { "name": "Tag 2" }] }
// Status (for new Status property type)
{ "status": { "name": "In progress" } }
// Text / Rich text
{ "rich_text": [{ "text": { "content": "Your text here" } }] }
// Number
{ "number": 42 }
// Date
{ "date": { "start": "2026-02-15" } }
{ "date": { "start": "2026-02-15T10:00:00", "end": "2026-02-15T12:00:00" } }
// Checkbox
{ "checkbox": true }
// Email
{ "email": "user@example.com" }
// URL
{ "url": "https://example.com" }
// Phone
{ "phone_number": "+1-555-123-4567" }
// Relation (link to another database entry)
{ "relation": [{ "id": "related-page-id-32chars" }] }
Security & Permissions
Critical Security Model:
- ✅ Integration ONLY sees pages you explicitly share
- ✅ You control access per page/database
- ✅ Token stored securely in
~/.openclaw/.env(never in code) - ❌ Never commit
NOTION_TOKENto git - ❌ Integration cannot access private teamspaces or other users' private pages
Best Practices:
- Use a dedicated integration (don't reuse personal integrations)
- Share minimum necessary pages (granular > broad)
- Rotate token if compromised via Notion integration settings
- Review shared connections periodically
Environment Setup
Add to ~/.openclaw/.env:
NOTION_TOKEN=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Or set per-command:
NOTION_TOKEN=secret_xxx node notion-cli.js ...
Error Handling
Common errors and fixes:
| Error | Cause | Fix |
|---|---|---|
| "API token is invalid" | Wrong token or integration deleted | Check token at notion.so/my-integrations |
| "object_not_found" | Page not shared with integration | Share page: Share → Add connections |
| "validation_error" | Property format incorrect | Check property type in database |
| "rate_limited" | Too many requests | Add delay between requests |
Quick Install (One Command)
cd ~/.agents/skills/notion
./install.sh
Manual install (if above fails):
cd ~/.agents/skills/notion
npm install
That's it! No build step required for the standalone version.
Quick Test
# After setting NOTION_TOKEN in ~/.openclaw/.env
node notion-cli.js test
Smart ID Resolution
Reference entries by Notion auto-ID (e.g., #3) or direct UUID.
By Notion ID (Recommended for Manual Use)
Use the number you see in your database's ID column:
# Get entry #3
node notion-cli.js get-page '#3' DATABASE_ID
# Add content to entry #3
node notion-cli.js append-body '#3' --database DATABASE_ID \
--text "Research notes" --type h2
# Add bullet to entry #3
node notion-cli.js append-body '#3' --database DATABASE_ID \
--text "Key finding" --type bullet
By Direct UUID (For Automation)
# Using full UUID from Notion URL
node notion-cli.js get-page 2fb3e4ac...
node notion-cli.js append-body 2fb3e4ac... \
--text "Content" --type paragraph
Auto-detection: Starts with # = Notion ID lookup. 32-char hex = Direct UUID.
Pro Tip: Add an ID property (type: unique ID) to auto-number entries as #1, #2, #3...
Page Body Editing
Add rich content to page bodies, not just properties.
Append Content Blocks
# Add heading
node notion-cli.js append-body PAGE_ID --text "Research Summary" --type h2
# Add paragraph (default)
node notion-cli.js append-body PAGE_ID --text "Detailed findings go here..."
# Add bullet list item
node notion-cli.js append-body PAGE_ID --text "First key finding" --type bullet
# Add numbered list item
node notion-cli.js append-body PAGE_ID --text "Step one description" --type numbered
# Add TODO checkbox
node notion-cli.js append-body PAGE_ID --text "Create video script" --type todo
# Add quote
node notion-cli.js append-body PAGE_ID --text "Important quote from source" --type quote
# Add code block
node notion-cli.js append-body PAGE_ID --text "const result = optimizeSupports();" --type code --lang javascript
Supported Block Types
| Type | Description | Example Use |
|---|---|---|
paragraph |
Regular text (default) | Descriptions, explanations |
h1, h2, h3 |
Headings | Section organization |
bullet |
Bulleted list | Key findings, features |
numbered |
Numbered list | Step-by-step instructions |
todo |
Checkbox item | Action items, tasks |
quote |
Blockquote | Source citations |
code |
Code block | Snippets, commands |
divider |
Horizontal line | Section separation |
Get Page with Body Content
# Get full page including formatted body
node notion-cli.js get-page PAGE_ID
Returns:
- Page properties
- Formatted body blocks (type + content preview)
- Block count
Advanced: Raw JSON Blocks
For complex layouts, use raw Notion block JSON:
node notion-cli.js append-body PAGE_ID --blocks '[
{"object":"block","type":"heading_2","heading_2":{"rich_text":[{"text":{"content":"Research Notes"}}]}},
{"object":"block","type":"bulleted_list_item","bulleted_list_item":{"rich_text":[{"text":{"content":"Finding 1"}}]}},
{"object":"block","type":"code","code":{"rich_text":[{"text":{"content":"console.log(1)"}}],"language":"javascript"}}
]'
Advanced: Webhook Sync
For bidirectional sync (Notion changes → OpenClaw):
- Set up Notion webhook integration (requires Notion partner account)
- Configure webhook endpoint to your OpenClaw Gateway
- Skill processes incoming webhooks and updates memory files
See references/webhooks.md for implementation details.
Need help? Check your Notion integration settings at https://www.notion.so/my-integrations
Using in OpenClaw
Quick Setup
# 1. Install
cd ~/.agents/skills/notion
npm install
# 2. Configure token
echo "NOTION_TOKEN=secret_xxxxxxxxxx" >> ~/.openclaw/.env
# 3. Test connection
node notion-cli.js test
From OpenClaw Agent
// Query database
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js query-database YOUR_DB_ID`
});
// Add entry
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js add-entry YOUR_DB_ID \\
--title "New Content Idea" \\
--properties '{"Status":{"select":{"name":"Idea"}}}'`
});
// Search
await exec({
command: `node ~/.agents/skills/notion/notion-cli.js search "tree support"`
});
Cron Job Usage
Update your Research Topic Scout to push to Notion:
"message": "Research trends and add to Notion:
node ~/.agents/skills/notion/notion-cli.js add-entry DB_ID
--title '<title>'
--properties '{...,\"Platform\":{\"multi_select\":[{\"name\":\"X\"}]}}'"