> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nekt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notion as a data source

> Bring data from Notion to Nekt.

Notion is the AI workspace that works for you - a productivity platform where teams can create docs, wikis, projects, and manage knowledge in one place. It's widely used by teams for documentation, project management, and collaboration.

<img width="200" src="https://mintcdn.com/nekt/3MFKt2g7jzqFpztO/assets/logo/logo-notion.png?fit=max&auto=format&n=3MFKt2g7jzqFpztO&q=85&s=45a2c1ddbe51799e34279440cf834cb7" data-path="assets/logo/logo-notion.png" />

## Configuring Notion as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the **Notion** option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

Nekt supports Notion OAuth, making the setup process simple and secure. You just need to authenticate with your Notion account.

1. Click **"Notion Authorization"** when prompted
2. You'll be redirected to Notion's authorization page
3. Sign in to your Notion account if you haven't already
4. Review the permissions that Nekt is requesting
5. Click **"Allow"** to grant access to your Notion workspace
6. You'll be redirected back to Nekt with your account connected

The OAuth process automatically handles authentication, token refreshes, and gives Nekt access to the databases you have permission to view in your Notion workspace.

**Important**

* The OAuth connection will give Nekt access to databases based on your user permissions in the Notion workspace.
* You can revoke access at any time from your Notion workspace settings.
* Only connect workspaces that contain the data you need for your analytics.

After you authorize Nekt, define from when you want to extract records by setting the **Start date** parameter and click **Next**.

### 2. Select streams

The Notion connector creates four types of data streams:

**Databases Stream**

* **Stream name**: `databases`
* **Purpose**: Lists all databases accessible to your Notion integration
* **Use case**: Discover what databases are available in your Notion workspace

**Database Content Streams**

* **Stream pattern**: `database_{database_id}`
* **Purpose**: Extracts the actual content (pages/rows) from each individual database
* **Use case**: Get the data stored within your Notion databases

**Pages Stream**

* **Stream name**: `pages`
* **Purpose**: Fetches all pages via the Notion Search API, including their full body content (blocks)
* **Use case**: Extract full documentation, wiki entries, and page contents from your workspace

**Comments Stream**

* **Stream name**: `comments`
* **Purpose**: Fetches all comments associated with your pages
* **Use case**: Extract discussions, feedback, and page comments from your workspace

Choose which data streams you want to sync - you can select all streams or pick specific ones that matter most to you.

> Tip: The stream can be found more easily by typing its name.

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.

* **Layer**: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: a folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: we suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: you can choose between INCREMENTAL and FULL\_TABLE.
  * **Incremental sync**: The connector supports incremental synchronization for database content streams and the pages stream using Notion's `last_edited_time`. Only extracts pages that have been created or modified since the last sync.
  * **Full sync**: Extracts all pages from the database every time.

<Note>
  The `databases` stream always performs a full sync since it's just listing available databases.
</Note>

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/get-started/core-concepts/triggers), consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times).

Optionally, you can define some additional settings:

* Configure **Delta Log Retention** and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an **Additional [Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync)**. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

<Warning>For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.</Warning>

# Streams and Fields

Below you'll find all available data streams from Notion and their corresponding fields:

<AccordionGroup>
  <Accordion title="Databases">
    The `databases` stream includes the following properties for each database:

    | Field              | Type    | Description                                                             |
    | :----------------- | :------ | :---------------------------------------------------------------------- |
    | `id`               | String  | Unique identifier for the database                                      |
    | `title`            | String  | Stringified JSON containing the database title information              |
    | `object`           | String  | Always "database" for database objects                                  |
    | `properties`       | String  | Stringified JSON of the database schema/properties                      |
    | `created_time`     | String  | When the database was created                                           |
    | `created_by`       | String  | Stringified JSON of the user who created the database                   |
    | `last_edited_by`   | String  | Stringified JSON of the user who last edited the database               |
    | `last_edited_time` | String  | When the database was last modified                                     |
    | `cover`            | String  | Stringified JSON of the database cover image information                |
    | `icon`             | String  | Stringified JSON of the database icon (emoji or image)                  |
    | `parent`           | String  | Stringified JSON of the information about where the database is located |
    | `url`              | String  | Internal Notion URL for the database                                    |
    | `public_url`       | String  | Public URL if the database is shared                                    |
    | `archived`         | Boolean | Whether the database is archived                                        |
    | `in_trash`         | Boolean | Whether the database is in trash                                        |
  </Accordion>

  <Accordion title="Database Content">
    Each `database_{database_id}` content stream includes:

    | Field              | Type    | Description                                                                      |
    | :----------------- | :------ | :------------------------------------------------------------------------------- |
    | `id`               | String  | Unique identifier for the page/row                                               |
    | `object`           | String  | Always "page" for database entries                                               |
    | `last_edited_time` | String  | When the page was last modified (used for incremental sync)                      |
    | `properties`       | String  | Stringified JSON containing all the page properties based on the database schema |
    | `created_time`     | String  | When the page was created                                                        |
    | `created_by`       | String  | Stringified JSON of the user who created the page                                |
    | `last_edited_by`   | String  | Stringified JSON of the user who last edited the page                            |
    | `cover`            | String  | Stringified JSON of the page cover image information                             |
    | `icon`             | String  | Stringified JSON of the page icon (emoji or image)                               |
    | `parent`           | String  | Stringified JSON of the reference to the parent database                         |
    | `archived`         | Boolean | Whether the page is archived                                                     |
    | `in_trash`         | Boolean | Whether the page is in trash                                                     |
    | `url`              | String  | Internal Notion URL for the page                                                 |
    | `public_url`       | String  | Public URL if the page is shared                                                 |
  </Accordion>

  <Accordion title="Pages">
    The pages stream fetches all pages via the Notion Search API with full content retrieval. It includes:

    | Field              | Type    | Description                                                       |
    | :----------------- | :------ | :---------------------------------------------------------------- |
    | `id`               | String  | Unique identifier of the page.                                    |
    | `object`           | String  | Type classification of the record.                                |
    | `is_archived`      | Boolean | Whether the page is archived.                                     |
    | `created_time`     | String  | Timestamp when the page was created.                              |
    | `last_edited_time` | String  | Timestamp when the page was last updated.                         |
    | `created_by`       | String  | Stringified JSON of the user who created the page.                |
    | `last_edited_by`   | String  | Stringified JSON of the user who last edited the page.            |
    | `cover`            | String  | Stringified JSON of the cover image for the page.                 |
    | `icon`             | String  | Stringified JSON of the icon for the page.                        |
    | `parent`           | String  | Stringified JSON of the parent of the page.                       |
    | `properties`       | String  | Property values of the page represented as a JSON string.         |
    | `content`          | String  | Page body content (block children) represented as a JSON string.  |
    | `archived`         | Boolean | Whether the page is archived (deprecated in favor of `in_trash`). |
    | `in_trash`         | Boolean | Whether the page is in trash.                                     |
    | `url`              | String  | URL of the page.                                                  |
    | `public_url`       | String  | Public URL of the page (if published publicly).                   |
  </Accordion>

  <Accordion title="Comments">
    The comments stream fetches discussions and comments linked to the fetched pages. It includes:

    | Field              | Type   | Description                                                                |
    | :----------------- | :----- | :------------------------------------------------------------------------- |
    | `id`               | String | Unique identifier of the comment.                                          |
    | `parent`           | String | Stringified JSON containing parent reference data.                         |
    | `discussion_id`    | String | Identifier for the discussion thread.                                      |
    | `rich_text`        | String | Stringified JSON array of rich text objects representing the comment body. |
    | `created_time`     | String | Timestamp when the comment was created.                                    |
    | `last_edited_time` | String | Timestamp when the comment was last modified.                              |
    | `created_by`       | String | Stringified JSON of the user who created the comment.                      |
    | `page_id`          | String | The ID of the page the comment belongs to (mapped via parent context).     |
  </Accordion>
</AccordionGroup>

# Data Model

The following diagram illustrates the relationships between the core data streams in Notion.

```mermaid theme={null}
erDiagram
    DATABASES {
        string id PK
    }
    DATABASE_CONTENT {
        string id PK
        string database_id FK
    }
    PAGES {
        string id PK
    }
    COMMENTS {
        string id PK
        string page_id FK
    }
    
    DATABASES ||--o{ DATABASE_CONTENT : contains
    PAGES ||--o{ COMMENTS : has
```

## Implementation Notes

### API Limits & Performance

* **Connection Pooling**: The connector uses connection pooling to prevent socket exhaustion during large data extractions. This ensures stable and reliable syncs without connection drops when fetching high volumes of records, particularly from heavily nested structures like the `pages` and `comments` streams.

### Transformation Requirements

* **Properties parsing**: All page properties (including custom columns defined in your Notion databases) are serialized into the `properties` JSON string. To use these fields in your analysis, you will need to parse the JSON in your SQL transformations (e.g., using `JSON_EXTRACT` in Athena or `JSON_VALUE` in BigQuery) to expose them as individual columns.
* **Titles and text**: Nested structures like titles, user objects, or rich text are exported as stringified JSON blocks and might require further extraction depending on your database engine.

### Authentication Limits

* Nekt securely manages the Notion OAuth integration natively in the platform. Refresh tokens are seamlessly updated and evaluated during internal system validations to guarantee uninterrupted extractions. Ensure your connected user retains the necessary read permissions over the source Notion databases.

## Skills for agents

<Snippet file="agent-skills-intro.mdx" />

<Card title="Download Notion skills file" icon="wand-magic-sparkles" href="/sources/notion.md">
  Notion connector documentation as plain markdown, for use in AI agent contexts.
</Card>
