← Back to Skills Marketplace
robansuini

Notion Sync

by robansuini · GitHub ↗ · v2.5.3 · MIT-0
cross-platform ✓ Security Clean
3824
Downloads
6
Stars
23
Active Installs
16
Versions
Install in OpenClaw
/install notion-sync
Description
Bi-directional sync and management for Notion pages and databases. Use when working with Notion workspaces for collaborative editing, research tracking, proj...
README (SKILL.md)

Notion Sync

Bi-directional sync between markdown files and Notion pages, plus database management utilities for research tracking and project management.

Upgrading

From v2.0: Replace --token "ntn_..." with --token-file, --token-stdin, or NOTION_API_KEY env var. Bare --token is no longer accepted (credentials should never appear in process listings).

From v1.x: See v2.0 changelog for migration details.

Requirements

  • Node.js v18 or later
  • A Notion integration token (starts with ntn_ or secret_)

Setup

  1. Go to https://www.notion.so/my-integrations

  2. Create a new integration (or use an existing one)

  3. Copy the "Internal Integration Token"

  4. Pass the token using one of these methods (priority order used by scripts):

    Option A — Token file (recommended):

    echo "ntn_your_token" > ~/.notion-token && chmod 600 ~/.notion-token
    node scripts/search-notion.js "query" --token-file ~/.notion-token
    

    Option B — Stdin pipe:

    echo "$NOTION_API_KEY" | node scripts/search-notion.js "query" --token-stdin
    

    Option C — Environment variable:

    export NOTION_API_KEY="ntn_your_token"
    node scripts/search-notion.js "query"
    

    Auto default: If ~/.notion-token exists, scripts use it automatically even without --token-file.

  5. Share your Notion pages/databases with the integration:

    • Open the page/database in Notion
    • Click "Share" → "Invite"
    • Select your integration

JSON Output Mode

All scripts support a global --json flag.

  • Suppresses progress logs written to stderr
  • Keeps stdout machine-readable for automation
  • Errors are emitted as JSON: { "error": "..." }

Example:

node scripts/query-database.js \x3Cdb-id> --limit 5 --json

Path Safety Mode

Scripts that read/write local files are restricted to the current working directory by default.

  • Prevents accidental reads/writes outside the intended workspace
  • Applies to: md-to-notion.js, add-to-database.js, notion-to-md.js, watch-notion.js
  • Override intentionally with --allow-unsafe-paths

Examples:

# Default (safe): path must be inside current workspace
node scripts/md-to-notion.js docs/draft.md \x3Cparent-id> "Draft"

# Intentional override (outside workspace)
node scripts/notion-to-md.js \x3Cpage-id> ~/Downloads/export.md --allow-unsafe-paths

Core Operations

1. Search Pages and Databases

Search across your Notion workspace by title or content.

node scripts/search-notion.js "\x3Cquery>" [--filter page|database] [--limit 10] [--json]

Examples:

# Search for newsletter-related pages
node scripts/search-notion.js "newsletter"

# Find only databases
node scripts/search-notion.js "research" --filter database

# Limit results
node scripts/search-notion.js "AI" --limit 5

Output:

[
  {
    "id": "page-id-here",
    "object": "page",
    "title": "Newsletter Draft",
    "url": "https://notion.so/...",
    "lastEdited": "2026-02-01T09:00:00.000Z"
  }
]

2. Query Databases with Filters

Query database contents with advanced filters and sorting.

node scripts/query-database.js \x3Cdatabase-id> [--filter \x3Cjson>] [--sort \x3Cjson>] [--limit 10] [--json]

Examples:

# Get all items
node scripts/query-database.js xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Filter by Status = "Complete"
node scripts/query-database.js \x3Cdb-id> \
  --filter '{"property": "Status", "select": {"equals": "Complete"}}'

# Filter by Tags containing "AI"
node scripts/query-database.js \x3Cdb-id> \
  --filter '{"property": "Tags", "multi_select": {"contains": "AI"}}'

# Sort by Date descending
node scripts/query-database.js \x3Cdb-id> \
  --sort '[{"property": "Date", "direction": "descending"}]'

# Combine filter + sort
node scripts/query-database.js \x3Cdb-id> \
  --filter '{"property": "Status", "select": {"equals": "Complete"}}' \
  --sort '[{"property": "Date", "direction": "descending"}]'

Common filter patterns:

  • Select equals: {"property": "Status", "select": {"equals": "Done"}}
  • Multi-select contains: {"property": "Tags", "multi_select": {"contains": "AI"}}
  • Date after: {"property": "Date", "date": {"after": "2024-01-01"}}
  • Checkbox is true: {"property": "Published", "checkbox": {"equals": true}}
  • Number greater than: {"property": "Count", "number": {"greater_than": 100}}

3. Update Page Properties

Update properties for database pages (status, tags, dates, etc.).

node scripts/update-page-properties.js \x3Cpage-id> \x3Cproperty-name> \x3Cvalue> [--type \x3Ctype>] [--json]

Supported types: select, multi_select, checkbox, number, url, email, date, rich_text

Examples:

# Set status
node scripts/update-page-properties.js \x3Cpage-id> Status "Complete" --type select

# Add multiple tags
node scripts/update-page-properties.js \x3Cpage-id> Tags "AI,Leadership,Research" --type multi_select

# Set checkbox
node scripts/update-page-properties.js \x3Cpage-id> Published true --type checkbox

# Set date
node scripts/update-page-properties.js \x3Cpage-id> "Publish Date" "2024-02-01" --type date

# Set URL
node scripts/update-page-properties.js \x3Cpage-id> "Source URL" "https://example.com" --type url

# Set number
node scripts/update-page-properties.js \x3Cpage-id> "Word Count" 1200 --type number

4. Batch Update

Batch update a single property across multiple pages in one command.

Mode 1 — Query + Update:

node scripts/batch-update.js \x3Cdatabase-id> \x3Cproperty-name> \x3Cvalue> --filter '\x3Cjson>' [--type select] [--dry-run] [--limit 100]

Example:

node scripts/batch-update.js \x3Cdb-id> Status Review \
  --filter '{"property":"Status","select":{"equals":"Draft"}}' \
  --type select

Mode 2 — Page IDs from stdin:

echo "page-id-1\
page-id-2\
page-id-3" | \
  node scripts/batch-update.js --stdin \x3Cproperty-name> \x3Cvalue> [--type select] [--dry-run]

Features:

  • --dry-run: prints pages that would be updated (with current property value) without writing
  • --limit \x3Cn>: max pages to process (default 100)
  • Pagination in query mode (has_more/next_cursor) up to limit
  • Rate-limit friendly updates (300ms between page updates)
  • Progress and summary on stderr, JSON result array on stdout

5. Markdown → Notion Sync

Push markdown content to Notion with full formatting support.

node scripts/md-to-notion.js \
  "\x3Cmarkdown-file-path>" \
  "\x3Cnotion-parent-page-id>" \
  "\x3Cpage-title>" [--json] [--allow-unsafe-paths]

Example:

node scripts/md-to-notion.js \
  "projects/newsletter-draft.md" \
  "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
  "Newsletter Draft - Feb 2026"

Supported formatting:

  • Headings (H1-H3)
  • Bold/italic text
  • Links
  • Bullet lists
  • Code blocks with syntax highlighting
  • Horizontal dividers
  • Paragraphs

Features:

  • Batched uploads (100 blocks per request)
  • Automatic rate limiting (350ms between batches)
  • Rich text is automatically chunked to Notion's 2000-character limit (including bold/italic/link spans)
  • Returns Notion page URL and ID

Output:

Parsed 294 blocks from markdown
✓ Created page: https://www.notion.so/[title-and-id]
✓ Appended 100 blocks (100-200)
✓ Appended 94 blocks (200-294)

✅ Successfully created Notion page!

6. Notion → Markdown Sync

Pull Notion page content and convert to markdown.

node scripts/notion-to-md.js \x3Cpage-id> [output-file] [--json] [--allow-unsafe-paths]

Example:

node scripts/notion-to-md.js \
  "abc123-example-page-id-456def" \
  "newsletter-updated.md"

Features:

  • Converts Notion blocks to markdown
  • Preserves formatting (headings, lists, code, quotes)
  • Optional file output (writes to file or stdout)

7. Change Detection & Monitoring

Monitor Notion pages for edits and compare with local markdown files.

node scripts/watch-notion.js "\x3Cpage-id>" "\x3Clocal-markdown-path>" [--state-file \x3Cpath>] [--json] [--allow-unsafe-paths]

Example:

node scripts/watch-notion.js \
  "abc123-example-page-id-456def" \
  "projects/newsletter-draft.md"

State tracking: By default maintains state in memory/notion-watch-state.json (relative to current working directory). You can override with --state-file \x3Cpath> (supports ~ expansion):

node scripts/watch-notion.js "\x3Cpage-id>" "\x3Clocal-path>" --state-file ~/.cache/notion-watch-state.json

Default state schema:

{
  "pages": {
    "\x3Cpage-id>": {
      "lastEditedTime": "2026-01-30T08:57:00.000Z",
      "lastChecked": "2026-01-31T19:41:54.000Z",
      "title": "Your Page Title"
    }
  }
}

Output:

{
  "pageId": "\x3Cpage-id>",
  "title": "Your Page Title",
  "lastEditedTime": "2026-01-30T08:57:00.000Z",
  "hasChanges": false,
  "localPath": "/path/to/your-draft.md",
  "actions": ["✓ No changes since last check"]
}

Automated monitoring: Schedule periodic checks using cron, CI pipelines, or any task scheduler:

# Example: cron job every 2 hours during work hours
0 9-21/2 * * * cd /path/to/workspace && node scripts/watch-notion.js "\x3Cpage-id>" "\x3Clocal-path>"

The script outputs JSON — pipe it to any notification system when hasChanges is true.

8. Database Management

Add Markdown Content to Database

Add a markdown file as a new page in any Notion database.

node scripts/add-to-database.js \x3Cdatabase-id> "\x3Cpage-title>" \x3Cmarkdown-file-path> [--json] [--allow-unsafe-paths]

Examples:

# Add research output
node scripts/add-to-database.js \
  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
  "Research Report - Feb 2026" \
  projects/research-insights.md

# Add project notes
node scripts/add-to-database.js \
  \x3Cproject-db-id> \
  "Sprint Retrospective" \
  docs/retro-2026-02.md

# Add meeting notes
node scripts/add-to-database.js \
  \x3Cnotes-db-id> \
  "Weekly Team Sync" \
  notes/sync-2026-02-06.md

Features:

  • Creates database page with title property
  • Converts markdown to Notion blocks (headings, paragraphs, dividers)
  • Handles large files with batched uploads
  • Returns page URL for immediate access

Note: Additional properties (Type, Tags, Status, etc.) must be set manually in Notion UI after creation.

Inspect Database Schema

node scripts/get-database-schema.js \x3Cdatabase-id> [--json]

Example output:

{
  "object": "database",
  "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "title": [{"plain_text": "Ax Resources"}],
  "properties": {
    "Name": {"type": "title"},
    "Type": {"type": "select"},
    "Tags": {"type": "multi_select"}
  }
}

Use when:

  • Setting up new database integrations
  • Debugging property names/types
  • Understanding database structure

Archive Pages

node scripts/delete-notion-page.js \x3Cpage-id> [--json]

Note: This archives the page (sets archived: true), not permanent deletion.

Common Workflows

Collaborative Editing Workflow

  1. Push local draft to Notion:

    node scripts/md-to-notion.js draft.md \x3Cparent-id> "Draft Title"
    
  2. User edits in Notion (anywhere, any device)

  3. Monitor for changes:

    node scripts/watch-notion.js \x3Cpage-id> \x3Clocal-path>
    # Returns hasChanges: true when edited
    
  4. Pull updates back:

    node scripts/notion-to-md.js \x3Cpage-id> draft-updated.md
    
  5. Repeat as needed (update same page, don't create v2/v3/etc.)

Research Output Tracking

  1. Generate research locally (e.g., via sub-agent)

  2. Sync to Notion database:

    node scripts/add-research-to-db.js
    
  3. User adds metadata in Notion UI (Type, Tags, Status properties)

  4. Access from anywhere via Notion web/mobile

Page ID Extraction

From Notion URL: https://notion.so/Page-Title-abc123-example-page-id-456def

Extract: abc123-example-page-id-456def (last part after title)

Or use the 32-char format: abc123examplepageid456def (hyphens optional)

Limitations

  • Property updates: Database properties (Type, Tags, Status) must be added manually in Notion UI after page creation. API property updates can be temperamental with inline databases.
  • Block limits: Very large markdown files (>1000 blocks) may take several minutes to sync due to rate limiting.
  • Formatting: Some complex markdown (tables, nested lists >3 levels) may not convert perfectly.

Troubleshooting

"Could not find page" error:

  • Ensure page/database is shared with your integration
  • Check page ID format (32 chars, alphanumeric + hyphens)

"Module not found" error:

  • Scripts use built-in Node.js https module (no npm install needed)
  • Ensure running from the skill's directory (where scripts/ lives)

Rate limiting:

  • Notion API has rate limits (~3 requests/second)
  • Scripts handle this automatically with 350ms delays between batches

Resources

scripts/

Core Sync:

  • md-to-notion.js - Markdown → Notion sync with full formatting
  • notion-to-md.js - Notion → Markdown conversion
  • watch-notion.js - Change detection and monitoring

Search & Query:

  • search-notion.js - Search pages and databases by query
  • query-database.js - Query databases with filters and sorting
  • update-page-properties.js - Update database page properties
  • batch-update.js - Batch update one property across many pages (query or stdin IDs)

Database Management:

  • add-to-database.js - Add markdown files as database pages
  • get-database-schema.js - Inspect database structure
  • delete-notion-page.js - Archive pages

Utilities:

  • notion-utils.js - Shared utilities (error handling, property formatting, API requests)

All scripts use only built-in Node.js modules (https, fs) - no external dependencies required.

references/

  • database-patterns.md - Common database schemas and property patterns
Usage Guidance
This skill appears to do exactly what it claims: local Node.js scripts that call api.notion.com using a Notion integration token. Before installing or running: 1) Provide a dedicated Notion integration token (ntn_/secret_) and share only the pages/databases you want the integration to access. 2) Be aware scripts will auto-read ~/.notion-token if it exists — remove or lock that file (chmod 600) if you don't want it used. 3) The default path-safety prevents reads/writes outside the current workspace; only use --allow-unsafe-paths intentionally. 4) Batch-update operations can modify many pages — use --dry-run first. 5) The code makes only HTTPS requests to api.notion.com and performs local file I/O; if you want extra assurance, review the included scripts locally before running.
Capability Analysis
Type: OpenClaw Skill Name: notion-sync Version: 2.5.3 The notion-sync skill bundle is a well-structured set of tools for interacting with the Notion API using only built-in Node.js modules. It implements several security best practices, including a 'Path Safety Mode' in `notion-utils.js` to prevent path traversal and secure credential handling that avoids exposing tokens in process listings. The code logic is transparent, lacks external dependencies, and strictly aligns with the stated purpose of managing Notion workspaces.
Capability Assessment
Purpose & Capability
Name/description (Notion sync) align with required binary (node) and requested environment variable (NOTION_API_KEY). The scripts implement expected features (search, query, md↔Notion sync, watch) and do not request unrelated cloud credentials or services.
Instruction Scope
SKILL.md and scripts limit operations to the workspace by default (resolveSafePath) and document an explicit override (--allow-unsafe-paths). Scripts read a Notion token via --token-file, --token-stdin, ~/.notion-token, or NOTION_API_KEY — the auto-detection of ~/.notion-token is convenient but means a token in that file will be used without an explicit flag. Scripts read/write local files and a state file under memory/, which is consistent with their stated purpose.
Install Mechanism
No install spec; this is instruction+script-based and relies on Node.js on PATH. No downloads or external installers are included, so nothing is written/installed by the skill itself.
Credentials
Only NOTION_API_KEY (or an equivalent token via file/stdin) is required, which is appropriate for Notion API use. No other secrets or unrelated env vars are requested. Note: the scripts will read ~/.notion-token if present — ensure that file is only used if intended.
Persistence & Privilege
always:false and no special platform privileges. The skill writes state to a workspace-relative file (memory/notion-watch-state.json) and does not alter other skills or global agent config. Autonomous invocation is allowed by default (normal) but not combined with any elevated privileges.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install notion-sync
  3. After installation, invoke the skill by name or use /notion-sync
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v2.5.3
Workspace path safety guard + docs hardening; keeps scanner-aligned metadata and credential-safe token handling.
v2.5.2
Security hardening: workspace-scoped file path safety guards, explicit --allow-unsafe-paths override, docs metadata updates, and test file removed from distributed bundle.
v2.5.1
fix: enforce Notion 2000-char rich_text limit for markdown spans in parseMarkdownRichText to prevent validation errors on long content.
v2.5.0
feat: batch-update.js for bulk property updates (query+update and stdin modes, --dry-run, rate limiting). feat: --json output mode on all scripts for composable piping.
v2.4.0
feat: friendlier error messages, ~ expansion in --token-file, auto-detect ~/.notion-token, --state-file flag for watch-notion
v2.3.0
Add clawdis registry metadata: declares NOTION_API_KEY and node requirements. Scanner should now see matching metadata.
v2.2.0
Security: remove bare --token arg. Credentials only via --token-file, --token-stdin, or NOTION_API_KEY env var. Never exposed in process listings or shell history.
v2.1.0
Add --token-file, --token-stdin, and NOTION_API_KEY env var as secure token input methods. --token still works. 109 tests. Addresses VirusTotal credential exposure concern.
v2.0.0
BREAKING: --token required for all scripts (env var removed). Fully platform-agnostic, zero environment dependencies. 105 tests. See upgrade guide in SKILL.md.
v1.0.6
Remove non-standard env field from frontmatter to resolve scanner metadata inconsistency
v1.0.5
Added homepage, repository, and license to frontmatter for provenance verification. Addresses ClawHub scanner recommendation.
v1.0.4
Security scan fixes: declared NOTION_API_KEY env dependency, made fully platform-agnostic (removed all macOS/OpenClaw references), eliminated code duplication across 6 scripts, centralized shared utils, 100 unit tests, backwards-compatible exports
v1.0.3
- Added test script: `scripts/test-normalize.js` for normalization testing. - Improved functionality in `scripts/notion-to-md.js`. - Enhanced monitoring or change detection logic in `scripts/watch-notion.js`.
v1.0.2
- Replaced the old `add-research-to-db.js` script with a new, more general `add-to-database.js` script for adding markdown files as pages to any Notion database. - Updated documentation to reflect the more flexible workflow for adding content to databases. - Simplified example commands and removed hardcoded database IDs, making usage examples more portable. - Cleaned up references to removed scripts and clarified output and feature descriptions in core operation docs.
v1.0.1
Fix: Remove hardcoded environment-specific paths. Script now requires explicit arguments or environment variables for portability.
v1.0.0
Initial release: Bi-directional markdown to Notion sync with database management and change detection
Metadata
Slug notion-sync
Version 2.5.3
License MIT-0
All-time Installs 23
Active Installs 23
Total Versions 16
Frequently Asked Questions

What is Notion Sync?

Bi-directional sync and management for Notion pages and databases. Use when working with Notion workspaces for collaborative editing, research tracking, proj... It is an AI Agent Skill for Claude Code / OpenClaw, with 3824 downloads so far.

How do I install Notion Sync?

Run "/install notion-sync" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Notion Sync free?

Yes, Notion Sync is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Notion Sync support?

Notion Sync is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Notion Sync?

It is built and maintained by robansuini (@robansuini); the current version is v2.5.3.

💬 Comments