Skip to main content

Apache Airflow provider for Notion API integration

Project description

Airflow Notion Provider

This provider enables Apache Airflow to integrate with Notion API, allowing you to automate workflows involving Notion databases, pages, and other content.

API Version: This provider uses Notion API version 2025-09-03, which supports multi-source databases. See Migration Guide for upgrading from older versions.

Installation

pip install airflow-provider-notion

Configuration

  1. Get your Notion API token from Notion Integrations
    • New tokens use ntn_ prefix (after Sept 2024)
    • Legacy tokens with secret_ prefix still work
  2. Set the connection in Airflow:
    • Connection ID: notion_default
    • Connection Type: notion (custom type registered by this provider)
    • Password: YOUR_NOTION_API_TOKEN (format: ntn_xxxxx... or secret_xxxxx...)
    • Extra (optional): {"headers": {"Notion-Version": "2025-09-03"}}

Configuration Methods

Method 1: Airflow UI

Admin → Connections → Add Connection
- Connection Id: notion_default
- Connection Type: notion
- Password: ntn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Method 2: Environment Variable

export AIRFLOW_CONN_NOTION_DEFAULT='{"conn_type": "notion", "password": "ntn_YOUR_TOKEN"}'

Method 3: Airflow CLI

airflow connections add notion_default \
    --conn-type notion \
    --conn-password ntn_YOUR_NOTION_TOKEN

Operators

NotionQueryDatabaseOperator

Query a Notion database or data source and return the results.

Note: For API 2025-09-03+, prefer using data_source_id. If only database_id is provided, the operator will automatically discover the first data source.

from airflow.providers.notion.operators import NotionQueryDatabaseOperator

# Recommended: Use data_source_id
query_database = NotionQueryDatabaseOperator(
    task_id='query_notion_datasource',
    data_source_id='your-data-source-id',  # Preferred
    filter_params={
        'property': 'Status',
        'select': {
            'equals': 'Done'
        }
    },
    sorts=[
        {
            'property': 'Created',
            'direction': 'descending'
        }
    ],
    page_size=50,
    dag=dag
)

# Legacy: Auto-discover from database_id (backward compatible)
query_database_legacy = NotionQueryDatabaseOperator(
    task_id='query_notion_database',
    database_id='your-database-id',  # Auto-discovers first data source
    filter_params={
        'property': 'Status',
        'select': {
            'equals': 'Done'
        }
    },
    dag=dag
)

NotionCreatePageOperator

Create a new page in a Notion data source.

Note: For API 2025-09-03+, prefer using data_source_id. If only database_id is provided, the operator will automatically discover the first data source.

from airflow.providers.notion.operators import NotionCreatePageOperator

# Recommended: Use data_source_id
create_page = NotionCreatePageOperator(
    task_id='create_notion_page',
    data_source_id='your-data-source-id',  # Preferred
    properties={
        'Title': {
            'title': [
                {
                    'text': {
                        'content': 'New Task'
                    }
                }
            ]
        },
        'Status': {
            'select': {
                'name': 'In Progress'
            }
        }
    },
    children=[  # Optional page content
        {
            'object': 'block',
            'type': 'paragraph',
            'paragraph': {
                'rich_text': [{'type': 'text', 'text': {'content': 'Page content here'}}]
            }
        }
    ],
    dag=dag
)

# Legacy: Auto-discover from database_id (backward compatible)
create_page_legacy = NotionCreatePageOperator(
    task_id='create_notion_page_legacy',
    database_id='your-database-id',  # Auto-discovers first data source
    properties={...},
    dag=dag
)

NotionUpdatePageOperator

Update an existing Notion page.

from airflow.providers.notion.operators import NotionUpdatePageOperator

update_page = NotionUpdatePageOperator(
    task_id='update_notion_page',
    page_id='your-page-id',
    properties={
        'Status': {
            'select': {
                'name': 'Completed'
            }
        }
    },
    dag=dag
)

NotionSearchOperator

Search pages and databases in your Notion workspace.

Note: The Search API only returns pages and databases that the integration has permission to access.

from airflow.providers.notion.operators import NotionSearchOperator

# Search all pages
search_pages = NotionSearchOperator(
    task_id='search_all_pages',
    filter_object_type='page',  # Only return pages
    sort_direction='descending',  # Most recently edited first
    page_size=100,
    dag=dag
)

# Search with keyword
search_projects = NotionSearchOperator(
    task_id='search_projects',
    query='project',  # Search for pages containing "project"
    filter_object_type='page',
    page_size=50,
    dag=dag
)

# Search all databases
search_databases = NotionSearchOperator(
    task_id='search_databases',
    filter_object_type='database',  # Only return databases
    page_size=100,
    dag=dag
)

# Search everything (pages + databases)
search_all = NotionSearchOperator(
    task_id='search_all',
    page_size=50,  # No filter = returns both
    dag=dag
)

Hooks

NotionHook

The base hook for interacting with Notion API (version 2025-09-03).

from airflow.providers.notion.hooks import NotionHook

hook = NotionHook(notion_conn_id='notion_default')

# Search pages and databases
results = hook.search(
    query='project',  # Optional: search keyword
    filter_params={'property': 'object', 'value': 'page'},  # Optional: filter by type
    sort={'direction': 'descending', 'timestamp': 'last_edited_time'},
    page_size=100
)

# Get data sources for a database
db_info = hook.get_data_sources('database-id')
data_sources = db_info.get('data_sources', [])
data_source_id = data_sources[0]['id']

# Query data source (recommended)
results = hook.query_data_source(
    data_source_id='data-source-id',
    filter_params={...},
    sorts=[...],
    page_size=50
)

# Query database (legacy, auto-discovers first data source)
results = hook.query_database(database_id='database-id', filter_params={...})

# Create page with data_source_id (recommended)
page = hook.create_page(
    data_source_id='data-source-id',
    properties={...}
)

# Create page with database_id (legacy, auto-discovers first data source)
page = hook.create_page(database_id='database-id', properties={...})

# Update page (unchanged)
page = hook.update_page(page_id='page-id', properties={...})

# Get page
page = hook.get_page(page_id='page-id')

# Block operations
children = hook.get_block_children(block_id='block-id')
hook.append_block_children(block_id='block-id', children=[...])

Migration from Legacy API

This provider uses Notion API version 2025-09-03, which introduces multi-source databases. Key changes:

What Changed?

  1. Database → Data Source paradigm:

    • Old: One database = one data table
    • New: One database can contain multiple data sources (tables)
    • Each data source has its own ID and schema
  2. API Endpoints:

    • Old: POST /v1/databases/{database_id}/query
    • New: POST /v1/data_sources/{data_source_id}/query
  3. Parent Type for Pages:

    • Old: {"parent": {"database_id": "..."}}
    • New: {"parent": {"data_source_id": "..."}}

How to Migrate?

Option 1: Automatic Migration (Recommended)

  • Keep using database_id parameter
  • The provider automatically discovers the first data source
  • Works for single-source databases (most common case)
# No changes needed - backward compatible
query = NotionQueryDatabaseOperator(
    task_id='query',
    database_id='your-database-id',  # Auto-discovers data_source_id
    ...
)

Option 2: Explicit Data Source IDs

  • Get data source ID from database
  • Use data_source_id parameter explicitly
  • Required for multi-source databases
# Step 1: Get data source ID (one-time setup)
hook = NotionHook()
db_info = hook.get_data_sources('your-database-id')
data_source_id = db_info['data_sources'][0]['id']  # First data source

# Step 2: Use data_source_id in operators
query = NotionQueryDatabaseOperator(
    task_id='query',
    data_source_id=data_source_id,  # Explicit data source
    ...
)

Finding Your Data Source ID:

  1. In Notion app: Database Settings → Manage data sources → Copy data source ID
  2. Via API: GET /v1/databases/{database_id} returns data_sources array
  3. Via Hook: hook.get_data_sources(database_id)

Breaking Changes

If users add a second data source to a database in Notion, integrations using database_id will:

  • Still work with automatic discovery (uses first data source)
  • May not query the intended data source if multiple exist
  • Should be updated to use explicit data_source_id

Development

Install development dependencies:

pip install -e ".[dev]"

Run tests:

pytest tests/

Format code:

black airflow/

Check types:

mypy airflow/

License

Apache License 2.0

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

airflow_provider_notion-2.11.0.post8.tar.gz (29.0 kB view details)

Uploaded Source

Built Distribution

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

airflow_provider_notion-2.11.0.post8-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file airflow_provider_notion-2.11.0.post8.tar.gz.

File metadata

File hashes

Hashes for airflow_provider_notion-2.11.0.post8.tar.gz
Algorithm Hash digest
SHA256 b83ebbcdb7fc536ca32f147380282900791d90ddd4cdeb9b3b83a5b20807d551
MD5 478372790b73879f8d4bfdb2fd6150d0
BLAKE2b-256 afaf00e4a20530731a27c0adceed5d1f1ad48141d9f708e6f33b956841b4d11b

See more details on using hashes here.

File details

Details for the file airflow_provider_notion-2.11.0.post8-py3-none-any.whl.

File metadata

File hashes

Hashes for airflow_provider_notion-2.11.0.post8-py3-none-any.whl
Algorithm Hash digest
SHA256 69cc08e9fff5e4085dc0a56103d60539b5a977ad45c7f3359004bc8622d2a2f0
MD5 ff428711c7df18f6975bb20fef999354
BLAKE2b-256 d7345465d7d502f0242978ccd224c49d27963eecfe3779dcfa395ba70e64a97e

See more details on using hashes here.

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