Skip to main content

High-fidelity bidirectional Markdown ↔ Notion conversion and synchronization SDK

Project description

notionify

High-fidelity bidirectional Markdown ↔ Notion conversion and synchronization SDK for Python 3.10+.

CI Python 3.10+ License: MIT

Features

  • Markdown → Notion — Parse Markdown and create Notion pages with headings, lists, code blocks, tables, math equations, images, and more
  • Notion → Markdown — Export Notion pages back to clean Markdown
  • Diff sync — Update pages incrementally with minimal API calls using LCS-based diffing
  • Image pipeline — Automatic upload of local files, data URIs, and external URLs via the Notion file upload API
  • Async support — Full async client for high-throughput workflows
  • Typed errors — Every failure has a specific error class with actionable context
  • Retry & rate limiting — Built-in exponential backoff, jitter, and rate-limit compliance

Installation

pip install notionify

Quick Start

Create a page from Markdown

from notionify import NotionifyClient

with NotionifyClient(token="ntn_xxxxx") as client:
    result = client.create_page_with_markdown(
        parent_id="<page-or-database-id>",
        title="Meeting Notes",
        markdown="# Agenda\n\n- Review Q4 goals\n- **Action items**\n\n```python\nprint('hello')\n```",
    )
    print(result.page_id)

Append content to an existing page

client.append_markdown(
    target_id="<page-id>",
    markdown="## New Section\n\nAppended content with *formatting*.",
)

Update a page with diff sync

Only the changed blocks are updated — unchanged content is left untouched:

result = client.update_page_from_markdown(
    page_id="<page-id>",
    markdown=updated_markdown,
    strategy="diff",       # default; use "overwrite" to replace everything
)
print(f"Kept {result.blocks_kept}, inserted {result.blocks_inserted}, "
      f"deleted {result.blocks_deleted}")

Export a Notion page to Markdown

markdown = client.page_to_markdown("<page-id>", recursive=True)
print(markdown)

Async client

import asyncio
from notionify import AsyncNotionifyClient

async def main():
    async with AsyncNotionifyClient(token="ntn_xxxxx") as client:
        result = await client.create_page_with_markdown(
            parent_id="<page-id>",
            title="Async Page",
            markdown="# Created asynchronously\n\nWith full image support.",
        )
        print(result.page_id)

asyncio.run(main())

Configuration

All options are passed as keyword arguments to the client constructor:

client = NotionifyClient(
    token="ntn_xxxxx",
    math_strategy="equation",           # "equation" | "code" | "latex_text"
    image_upload=True,                   # auto-upload local/data-URI images
    image_fallback="skip",              # "skip" | "placeholder" | "raise"
    image_base_dir="/safe/path",        # restrict local image reads to this dir
    enable_tables=True,                  # convert Markdown tables to Notion tables
    retry_max_attempts=5,               # max retries on transient failures
    rate_limit_rps=3.0,                 # requests per second limit
    timeout_seconds=30.0,               # per-request timeout
)

See the API Reference for the full list of options.

Error Handling

All errors inherit from NotionifyError and carry structured context:

from notionify import NotionifyClient, NotionifyRateLimitError, NotionifyError

with NotionifyClient(token="ntn_xxxxx") as client:
    try:
        client.create_page_with_markdown(
            parent_id="<page-id>",
            title="Test",
            markdown="# Hello",
        )
    except NotionifyRateLimitError as e:
        print(f"Rate limited, retry after: {e.context}")
    except NotionifyError as e:
        print(f"[{e.code}] {e.message}")

Documentation

Development

# Clone and install dev dependencies
git clone https://github.com/notionify/notionify.git
cd notionify
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

# Lint and type-check
ruff check src/ tests/
mypy src/notionify  # strict mode via pyproject.toml

# Performance benchmarks
pytest tests/perf/ -v -s

License

MIT

Project details


Download files

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

Source Distribution

notionify-0.1.2.tar.gz (405.5 kB view details)

Uploaded Source

Built Distribution

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

notionify-0.1.2-py3-none-any.whl (99.2 kB view details)

Uploaded Python 3

File details

Details for the file notionify-0.1.2.tar.gz.

File metadata

  • Download URL: notionify-0.1.2.tar.gz
  • Upload date:
  • Size: 405.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for notionify-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5d613e49b277735acd62d52a4deb0687b68a221f2305e832c1215236e68c1e12
MD5 8f50b2e9d0168f070f706c4ff36f348c
BLAKE2b-256 a9809455d75ba7afb69368a9596f42c9488ec6fd762d8ee0908495179882147d

See more details on using hashes here.

Provenance

The following attestation bundles were made for notionify-0.1.2.tar.gz:

Publisher: publish.yml on nerdneilsfield/notionify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file notionify-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: notionify-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 99.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for notionify-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c81c3eec97d30649a10b9dfd46d73aa3c1db6c310676e544c38179c4103a2959
MD5 d501a88d0fc1432a66d0979436cff3ae
BLAKE2b-256 84e2e924abec21d04b7d66de66447e19251a277be3a69ee91c97e11626b0899d

See more details on using hashes here.

Provenance

The following attestation bundles were made for notionify-0.1.2-py3-none-any.whl:

Publisher: publish.yml on nerdneilsfield/notionify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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