Read and write Notion pages from your terminal — built for AI coding agents and developers.
# Homebrew (recommended)
brew tap andrzejchm/notion-cli
brew install notion-cli
# npm (alternative)
npm install -g @andrzejchm/notion-cli
notion auth login # choose your auth methodFetch and follow instructions from https://raw.githubusercontent.com/andrzejchm/notion-cli/main/docs/README.agents.md
notion search— find any page or database by titlenotion read— render any page as full-fidelity markdownnotion db query— filter, sort, and select columns from any databasenotion append— append markdown content to an existing pagenotion create-page— create a new page with markdown body, prints URL to stdoutnotion comment— add a comment to a page, block, or discussion thread- Agent-friendly — plain text tables by default;
--jsonfor machine-readable output - Flexible auth — interactive setup or
NOTION_API_TOKENenv var - Accepts URLs — pass full Notion URLs anywhere an ID is expected
# Search for a page, then read it
PAGE_ID=$(notion search "Q1 Planning" | jq -r '.[0].id')
notion read "$PAGE_ID"
# Query a database with filters
notion db query "$DB_ID" --filter "Status=In Progress" --sort "Priority:asc"
# Get JSON output for scripting / AI agents
notion db query "$DB_ID" --filter "Status=Done" | jq '.[] | .properties.Title'
# Append markdown blocks to an existing page
notion append "$PAGE_ID" -m "## Summary\nGenerated by AI agent."
# Create a new page and capture its URL
URL=$(notion create-page --parent "$PAGE_ID" --title "Meeting Notes" -m "# Agenda\n- Item 1")
echo "Created: $URL"
# Pipe content to a new page
my-summarize-command | notion create-page --parent "$PAGE_ID" --title "Auto Summary"
# Add a comment to a page
notion comment "$PAGE_ID" -m "Reviewed and approved."
# Reply to an existing discussion thread
notion comment --reply-to "$DISCUSSION_ID" -m "Agreed, let's proceed."
# Comment on a specific block
notion comment --block "$BLOCK_ID" -m "This section needs revision."
# List everything your integration can access
notion ls| Command | Description |
|---|---|
notion auth login |
Interactive auth setup — choose OAuth or integration token |
notion auth logout |
Remove a profile and all its credentials |
notion auth status |
Show current auth state |
notion auth list |
List all saved profiles |
notion auth use <name> |
Switch the active profile |
notion search <query> |
Search pages and databases by title (--sort asc|desc) |
notion ls |
List all accessible pages and databases (--sort asc|desc) |
notion open <id|url> |
Open a page in your browser |
notion read <id|url> |
Read a page as markdown |
notion db create --parent <id|url> --title <title> |
Create a new database with property definitions |
notion db schema <id|url> |
Show database property schema and valid values |
notion db query <id|url> |
Query database entries with filtering and sorting |
notion users |
List workspace members |
notion comments <id|url> |
Read page comments |
notion comment [id|url] -m <text> |
Add a comment to a page, block, or thread |
notion append <id|url> -m <markdown> |
Append markdown blocks to a page |
notion attach <id|url> <file> [files...] |
Upload and attach file(s) to a page |
notion edit-page <id|url> --find <old> --replace <new> |
Search-and-replace text on a page |
notion edit-page <id|url> -m <markdown> |
Replace entire page content |
notion create-page --parent <id|url> --title <title> |
Create a new page, prints URL |
notion update <id|url> --prop "Name=Value" |
Update properties on a page |
notion archive <id|url> |
Archive (trash) a page |
notion move <ids|urls...> --to <id|url> |
Move pages to a new parent page |
notion move <ids|urls...> --to-db <id|url> |
Move pages to a database parent |
notion completion bash|zsh|fish |
Install shell tab completion |
| Flag | Example | Description |
|---|---|---|
--caption <text> |
--caption "My screenshot" |
Caption for the file block(s) |
--type <type> |
--type image |
Override auto-detected block type (image|file|pdf|audio|video) |
--json |
--json |
Output JSON response |
Both commands accept a repeatable --file <path> option to attach local files after the markdown content is written:
# Append markdown and attach a file
notion append "$PAGE_ID" -m "See attached screenshot:" --file screenshot.png
# Create a page with an attached PDF
notion create-page --parent "$PAGE_ID" --title "Report" --file report.pdf
# Attach multiple files
notion append "$PAGE_ID" --file image.png --file data.csv| Flag | Example | Description |
|---|---|---|
--sort |
--sort desc |
Sort by last edited time (asc or desc) |
--type |
--type page |
Filter by object type (page or database) |
--cursor |
--cursor <cursor> |
Pagination cursor from a previous --next hint |
--json |
--json |
Force JSON output |
| Flag | Example | Description |
|---|---|---|
--parent |
--parent <id|url> |
Parent page ID or URL (required) |
--title |
--title "Tasks" |
Database title (required) |
--prop |
--prop "Status:select:To Do,Done" |
Property definition (repeatable) |
--json |
--json |
Output full JSON response |
Property syntax: Name:type[:options]. Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, people, files, created_time, last_edited_time. If no title property is defined, Name:title is added automatically.
| Flag | Example | Description |
|---|---|---|
--filter |
--filter "Status=Done" |
Filter by property value (repeatable) |
--sort |
--sort "Created:desc" |
Sort by property (:asc or :desc) |
--columns |
--columns "Title,Status" |
Only show specific columns |
--json |
--json |
Force JSON output |
The CLI auto-detects your context:
| Context | Default output | Override |
|---|---|---|
| Terminal (TTY) | Formatted tables, colored | --json for raw JSON |
| Piped / agent | Plain text tables | --json for raw JSON |
notion read always outputs markdown — in terminal and when piped.
Two authentication methods are available. If both are configured, OAuth takes precedence for API calls.
Start with the interactive setup:
notion auth login # choose OAuth or integration token| Method | Best for | Write attribution | Requires |
|---|---|---|---|
| OAuth user login | Write-heavy workflows, personal use | Your Notion account | Browser (or --manual for headless) |
| Integration token | CI, Docker, automated agents | Integration bot | Token from notion.so/profile/integrations |
NOTION_API_TOKEN env var |
CI/Docker without config files | Integration bot | Token set in environment |
Priority: NOTION_API_TOKEN env var → OAuth token → integration token (first found wins)
notion auth login # interactive selector — choose OAuth
notion auth login --manual # headless: prints URL, prompts to paste redirect
notion auth status # show current auth state
notion auth logout # remove profile and credentialsComments and pages are attributed to your actual Notion account. Access tokens expire after ~1 hour and are refreshed automatically.
notion auth login # interactive selector — choose "Integration token"
# or: environment variable (CI, Docker, agents — no profile needed)
export NOTION_API_TOKEN=ntn_your_token_hereWorks everywhere (CI, headless, agents). Write operations are attributed to the integration bot.
You must manually connect the integration to each page (⋯ → Add connections).
Token format: starts with ntn_ (new) or secret_ (legacy integrations).
Get a token: notion.so/profile/integrations/internal
notion auth list # list all profiles
notion auth use <name> # switch active profile
notion auth logout # remove a profile (interactive selector)
notion auth logout --profile <name> # remove specific profile directlyRead-only commands (search, read, db query, etc.) need Read content only.
Write commands require additional capabilities — enable in your integration settings (notion.so/profile/integrations/internal → your integration → Capabilities):
| Command | Required capabilities |
|---|---|
notion append |
Read content, Insert content |
notion attach |
Read content, Insert content |
notion create-page |
Read content, Insert content |
notion update |
Read content, Update content |
notion comment |
Read content, Insert content, Read comments, Insert comments |
Page not found (404): Share the page with your integration — open the page → ⋯ → Add connections.
Unauthorized (401): Run notion auth login to reconfigure, or check your NOTION_API_TOKEN.
Search returns nothing: Search is title-only. The page must also be shared with your integration.
Empty database query: Run notion db schema <id> first to see valid property names and values.
notion comment returns "Insufficient permissions": Enable Read comments and Insert comments in your integration capabilities: notion.so/profile/integrations/internal → your integration → Capabilities.
notion append / notion create-page returns "Insufficient permissions": Enable Insert content in your integration capabilities.
See docs/FEATURE-PARITY.md for a detailed comparison of this CLI's capabilities against the official Notion MCP server, with prioritized gaps and planned additions.
MIT © Andrzej Chmielewski
