Skip to main content

Better Notion

A pythonic, object-oriented SDK for the Notion API.

PyPI Python Tests Coverage


🚀 Quick Start

pip install better-notion
import asyncio
from better_notion import NotionAPI

async def main():
    async with NotionAPI(auth="secret_...") as api:
        # Get a page
        page = await api.pages.get("page_id")
        print(page.properties)

        # List pages in a database
        async for page in api.pages.iterate("database_id"):
            print(page.title)

asyncio.run(main())

✨ Why Better Notion?

  • 🎯 Object-Oriented: Work with entities, not JSON dicts
  • 🔋 Type-Safe: Property builders for compile-time safety
  • 📄 Paginated: Automatic cursor-based pagination
  • 🔍 Powerful Search: Search across your entire workspace
  • ⚡ Async-First: Built with asyncio and httpx for performance

📦 Installation

SDK Installation

# With pip
pip install better-notion

# With uv
uv pip install better-notion

CLI Installation

# Install with CLI support
pip install better-notion[cli]

# Or install everything
pip install better-notion[all]

The CLI provides a notion command for interacting with Notion from the terminal, designed primarily for AI agents.

CLI Status: ⚠️ Experimental - Under active development


💻 CLI Usage

The Better Notion CLI provides a command-line interface for interacting with Notion.

Installation

pip install better-notion[cli]

Basic Commands

# Show version
notion --version

# Check authentication status
notion auth status

# Show help
notion --help

Response Format

All CLI commands return JSON for programmatic parsing:

{
  "success": true,
  "data": {
    "id": "page_123",
    "title": "My Page"
  },
  "meta": {
    "version": "0.4.0",
    "timestamp": "2025-01-26T10:00:00Z",
    "rate_limit": {
      "remaining": 48,
      "reset_at": "2025-01-26T10:01:00Z"
    }
  }
}

Error Handling

Errors are returned with structured codes:

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Page not found",
    "retry": false
  },
  "meta": {...}
}

Exit Codes

  • 0 - Success
  • 1 - Generic error
  • 2 - Invalid input
  • 3 - Authentication error
  • 4 - Rate limit exceeded
  • 5 - Not found
  • 6 - Conflict

Note: The CLI is currently in experimental stage. See CLI Documentation for more details.


🔑 Authentication

Create an integration at notion.so/my-integrations to get your API token.

from better_notion import NotionAPI

api = NotionAPI(auth="secret_...")

📚 Features

Entities

All Notion objects are represented as Python entities:

  • Pages - Create, read, update, delete, archive
  • Blocks - Manipulate content blocks
  • Databases - Query and manage databases
  • Users - Retrieve user information

Property Builders

Type-safe builders for all Notion property types:

from better_notion._api.properties import Title, Select, Date, Checkbox

properties = {
    **Title("My Page").build(),
    **Select("Status", "In Progress").build(),
    **Date("Due Date", "2025-01-15").build(),
    **Checkbox("Done", False).build(),
}

Automatic Pagination

Memory-efficient iteration over large datasets:

async for page in api.pages.iterate("database_id"):
    # Processes pages lazily, not all at once
    process(page)

💡 Usage Examples

Creating a Page

from better_notion import NotionAPI
from better_notion._api.properties import Title, Text

async def create_page():
    async with NotionAPI(auth="secret_...") as api:
        page = await api.pages.create(
            parent={"database_id": "database_id"},
            properties={
                **Title("My New Page").build(),
                **Text("Notes", "Some notes").build(),
            }
        )
        print(f"Created page: {page.id}")

Updating a Page

from better_notion._api.properties import Select

async def update_page():
    async with NotionAPI(auth="secret_...") as api:
        page = await api.pages.get("page_id")

        # Update properties locally
        await page.update(
            **Select("Status", "Done").build()
        )

        # Save changes to Notion
        await page.save()

Working with Blocks

async def manipulate_blocks():
    async with NotionAPI(auth="secret_...") as api:
        page = await api.pages.get("page_id")

        # Get children blocks
        children = await page.blocks.children()

        # Append a new block
        await page.blocks.append(children=[
            {
                "object": "block",
                "type": "paragraph",
                "paragraph": {
                    "rich_text": [{"type": "text", "text": {"content": "New paragraph"}}]
                }
            }
        ])

Searching

async def search_pages():
    async with NotionAPI(auth="secret_...") as api:
        # Search for pages matching query
        async for result in api.search_iterate("my query"):
            if result["object"] == "page":
                print(result["properties"]["title"])

📖 API Reference

NotionAPI

The main client for interacting with Notion.

Methods:

  • search(query, *, filter, sort) - Search pages and blocks
  • search_iterate(query, *, filter, sort) - Iterate over search results

Collections:

  • api.pages - PageCollection
  • api.blocks - BlockCollection
  • api.databases - DatabaseCollection
  • api.users - UserCollection

Page

Properties:

  • id - Page ID
  • created_time - Creation datetime
  • last_edited_time - Last edited datetime
  • archived - Whether page is archived
  • properties - Page properties dict
  • blocks - BlockCollection for children

Methods:

  • await save() - Save changes to Notion
  • await delete() - Archive page
  • await reload() - Reload from Notion
  • await update(**kwargs) - Update properties locally

Block

Properties:

  • id - Block ID
  • type - Block type (paragraph, heading, etc.)
  • content - Block content

Methods:

  • await save() - Save changes to Notion
  • await delete() - Delete block
  • await reload() - Reload from Notion

Collections

PageCollection

  • await get(page_id) - Retrieve a page
  • await create(**kwargs) - Create a new page
  • await list(database_id, **kwargs) - List pages (first page)
  • iterate(database_id, **kwargs) - Iterate over all pages

BlockCollection

  • await get(block_id) - Retrieve a block
  • await children() - Get children blocks
  • await append(**kwargs) - Append new blocks

DatabaseCollection

  • await get(database_id) - Retrieve a database
  • await query(database_id, **kwargs) - Query a database
  • await create_page(database_id, **kwargs) - Create a page in database

UserCollection

  • await get(user_id) - Retrieve a user
  • await list() - List all users
  • await me() - Get current bot user

🤝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

Development

# Clone the repository
git clone https://github.com/nesalia-inc/better-notion.git

# Install with dev dependencies
uv sync

# Run tests
uv run pytest

# Run with coverage
uv run pytest --cov=better_notion

📝 License

This project is licensed under the MIT License - see the LICENSE file for details.


🔗 Links


🙏 Acknowledgments

Built with ❤️ using:

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

better_notion-2.8.16.tar.gz (283.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

better_notion-2.8.16-py3-none-any.whl (287.8 kB view details)

Uploaded Python 3

File details

Details for the file better_notion-2.8.16.tar.gz.

File metadata

  • Download URL: better_notion-2.8.16.tar.gz
  • Upload date:
  • Size: 283.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for better_notion-2.8.16.tar.gz
Algorithm Hash digest
SHA256 b056ae054ea597bda94c684c15d259edcc5025b17edc12707f5ff8db6bf0c323
MD5 2ae93a4b4dc2b67bff65ccbef6b9b553
BLAKE2b-256 58a46fb9d934dcafe2bc8834710cd1ba0a3f205117f1cd8de6d2003a6d8a4a6e

See more details on using hashes here.

File details

Details for the file better_notion-2.8.16-py3-none-any.whl.

File metadata

  • Download URL: better_notion-2.8.16-py3-none-any.whl
  • Upload date:
  • Size: 287.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for better_notion-2.8.16-py3-none-any.whl
Algorithm Hash digest
SHA256 c84e70a3b328f75a9e6a39c8f416d63051353061a76e6971290a5831c52c5716
MD5 eeea3d6c201dfeb557ea35efdd57f509
BLAKE2b-256 09e1292268db304b4a04c5c3860f84ba87cf882030012de1151408a0efbc7165

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2.8.16 This release

2 files

2.8.15

2 files

2.8.14

2 files

2.8.13

2 files

2.8.12

2 files

2.8.11

2 files

2.8.10

2 files

2.8.9

2 files

2.8.8

2 files

2.8.7

2 files

2.8.6

2 files

2.8.5

2 files

2.8.4

2 files

2.8.3

2 files

2.8.2

2 files

2.8.1

2 files

2.8.0

2 files

2.7.1

2 files

2.7.0

2 files

2.6.4

2 files

2.6.3

2 files

2.6.2

2 files

2.6.1

2 files

2.6.0

2 files

2.5.1

2 files

2.5.0

2 files

2.4.2

2 files

2.4.1

2 files

2.4.0

2 files

2.3.3

2 files

2.3.2

2 files

2.3.1

2 files

2.3.0

2 files

2.2.0

2 files

2.1.9

2 files

2.1.8

2 files

2.1.7

2 files

2.1.6

2 files

2.1.5

2 files

2.1.4

2 files

2.1.3

2 files

2.1.2

2 files

2.1.1

2 files

2.1.0

2 files

2.0.1

2 files

2.0.0

2 files

1.9.9

2 files

1.9.8

2 files

1.9.7

2 files

1.9.6

2 files

1.9.5

2 files

1.9.4

2 files

1.9.3

2 files

1.9.2

2 files

1.9.1

2 files

1.9.0

2 files

1.8.9

2 files

1.8.8

2 files

1.8.7

2 files

1.8.6

2 files

1.8.5

2 files

1.8.4

2 files

1.8.3

2 files

1.8.2

2 files

1.8.1

2 files

1.8.0

2 files

1.7.0

2 files

1.6.0

2 files

1.5.5

2 files

1.5.4

2 files

1.5.3

2 files

1.5.2

2 files

1.5.1

2 files

1.5.0

2 files

1.4.0

2 files

1.3.0

2 files

1.2.0

2 files

1.1.0

2 files

1.0.1

2 files

1.0.0

2 files

0.9.9

2 files

0.9.8

2 files

0.9.7

2 files

0.9.6

2 files

0.9.5

2 files

0.9.4

2 files

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

0.9.0

2 files

0.8.1

2 files

0.8.0

2 files

0.7.3

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.9

2 files

0.6.8

2 files

0.6.7

2 files

0.6.6

2 files

0.6.5

2 files

0.6.4

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page