notion-api-wrapper
v6.0.0
Published
Zero dependency Notion API client
Downloads
227
Maintainers
Readme
Notion API Wrapper
Zero dependency Notion API client.
Installation
npm install notion-api-wrapperOr your favorite package manager, in which case you probably know the command.
Getting Started
[!NOTE] Notion API version 2025-09-03 changed how databases work. Data Sources are now the primary way to access structured data in Notion. This package supports this new API version.
See the docs for more information.
Auth
Requests to the Notion API require an API token to authenticate.
Create new integration at https://www.notion.so/profile/integrations. You can revoke the Notion API token at any time in the same URL.
Give the integration permissions to read the databases and/or pages you want to access. You can do this in the databases or pages at:
⋯→Connections→ →Add connection→<Integration Name>.Make the Notion API token available as an environment variable under the name
NOTION_TOKEN. You may also pass it as a parameter to the functions using thenotionTokenoption.
CLI
To make obtaining block, page, database, and data source IDs easier, this package provides a CLI tool. Using the CLI is optional, you can also get the IDs from the URLs directly or data source IDs from the Notion app from database settings: Manage data sources.
npm install -g notion-api-wrapperYou can then use the naw command to fetch block, page, database, and data source IDs from a URL or database ID.
naw get page-id https://www.notion.so/a-page
naw get database-id https://www.notion.so/a-database
naw get block-id https://www.notion.so/a-page#a-block
naw fetch datasources https://www.notion.so/my-databaseThe naw fetch datasources command is the only one that requires authentication (NOTION_TOKEN environment variable), other commands just parse the URL.
Basics
Page Operations
This package provides helpers to retrieve, create, update, and trash pages.
import {
createPage,
retrievePage,
updatePage,
trashPage,
} from 'notion-api-wrapper';
const newPage = await createPage({
parent: {
data_source_id: DATA_SOURCE_ID,
},
properties: {},
content: [
{
type: 'paragraph',
paragraph: { rich_text: [{ text: { content: 'Hello, world!' } }] },
},
],
});
const existingPage = await retrievePage(newPage.id);
const updatedPage = await updatePage(newPage.id, { icon: { emoji: '🎁' } });
const trashedPage = await trashPage(newPage.id);Querying Data Sources
You can find the Data Source ID from the settings of the database page on Notion.
import { queryDataSource } from 'notion-api-wrapper';
const data = await queryDataSource(DATA_SOURCE_ID);If you want to explicitly pass the Notion API token as a parameter, you can do so with the notionToken option. If notionToken is not provided, the NOTION_TOKEN environment variable will be used.
import { queryDataSource } from 'notion-api-wrapper';
const data = await queryDataSource(DATA_SOURCE_ID, {
notionToken: NOTION_TOKEN,
});Filtering Results
You can use FilterBuilder to create filters that will be used in the query.
import { queryDataSource, FilterBuilder } from 'notion-api-wrapper';
const filterA: Filter = {
property: 'Done',
checkbox: {
equals: true,
},
};
const filterB: Filter = {
property: 'Tags',
multi_select: {
contains: 'A',
},
};
const filterC: Filter = {
property: 'Tags',
multi_select: {
contains: 'B',
},
};
const myFilter = new FilterBuilder()
.addFilter(filterA)
.addFilter(
new FilterBuilder().addFilter(filterB).addFilter(filterC).build('OR'),
)
.build('AND');
// property `Done` is true AND (property `Tags` contains `A` OR property `Tags` contains `B`)
const data = await queryDataSource(DATA_SOURCE_ID, {
filter: myFilter,
});Sorting Results
You can sort the results by specifying the sort option.
import { queryDataSource } from 'notion-api-wrapper';
const data = await queryDataSource(DATA_SOURCE_ID, {
sort: {
direction: 'ascending',
property: 'Name',
},
});By default the primary (title) property will be used for sorting.
Field and Property Options
There are options to remove built-in fields and properties from the results. Here is a kitchen sink example of that.
import { queryDataSource } from 'notion-api-wrapper';
const data = await queryDataSource(DATA_SOURCE_ID, {
propOptions: {
remove: {
userIds: true,
pageTimestamps: true,
url: true,
publicUrl: true,
objectType: true,
id: true,
icon: true,
cover: true,
archived: true,
parent: true,
inTrash: true,
customProps: ['Description', 'Priority'],
},
},
});You can remove all properties except certain ones by using the keep option.
import { queryDataSource } from 'notion-api-wrapper';
const data = await queryDataSource(DATA_SOURCE_ID, {
propOptions: {
keep: ['Name', 'Tags', 'Done'],
},
});Notion API responses can be quite verbose, so there are options to simplify the results.
import { queryDataSource } from 'notion-api-wrapper';
const data = await queryDataSource(DATA_SOURCE_ID, {
propOptions: {
simplifyProps: true,
simpleIcon: true,
},
});Data Source Search
You can easily search a Data Source for a matching page by using the searchFromDataSource function.
import { searchFromDataSource } from 'notion-api-wrapper';
const data = await searchFromDataSource(DATA_SOURCE_ID, {
query: 'kiwi',
});By default the search uses the Name property, but you can specify a different property. By default the search looks for exact matches, but you can modify that behavior too.
import { searchFromDataSource } from 'notion-api-wrapper';
const data = await searchFromDataSource(DATA_SOURCE_ID, {
query: 'Vegetab',
property: 'Name',
match: 'startsWith',
});Data Source Metadata
Data Source metadata can be obtained with the retrieveDataSource function. This supports some of the same options as the query functions.
import { retrieveDataSource } from 'notion-api-wrapper';
const columns = await retrieveDataSource(DATA_SOURCE_ID);Client
The NotionClient class provides an alternative way to access the functions described above.
import { NotionClient } from 'notion-api-wrapper';
const notion = new NotionClient({
notionToken: NOTION_TOKEN,
});
const dataSource = await notion.dataSources.retrieve(DATA_SOURCE_ID);
const data = await notion.dataSources.query(DATA_SOURCE_ID);
const matches = await notion.dataSources.search(DATA_SOURCE_ID, {
query: 'kiwi',
});
const created = await notion.pages.create({
parent: {
data_source_id: DATA_SOURCE_ID,
},
properties: {},
children: [],
});
const retrieved = await notion.pages.retrieve(created.id);
const updated = await notion.pages.update(created.id, {
icon: { emoji: '🎁' },
});
const trashed = await notion.pages.trash(created.id);Advanced Usage
Pagination
There is a function to query the Data Source in a paginated way. A single query returns at most 100 pages.
By default queryDataSource returns all pages in the Data Source. This may result in many requests to the Notion API. To avoid this, you can manually paginate the results.
import { queryDataSource } from 'notion-api-wrapper';
const { data, cursor } = await queryDataSource(DATA_SOURCE_ID, {
limit: 100,
});
const { data: data2 } = await queryDataSource(DATA_SOURCE_ID, {
limit: 100,
cursor,
});Data Source Iterator
While managing the pagination manually is possible,
the NotionDataSource class provides a more convenient way to iterate over the Data Source.
import { NotionDataSource } from 'notion-api-wrapper';
const ds = new NotionDataSource(DATA_SOURCE_ID);
for await (const page of ds.iterator()) {
console.log(page.id);
}By default the iterator yields each page individually. You can pass the yieldSize option to control the number of pages that will be yielded for each iteration. If you set yieldSize to a value other than the default of 1, you will get the results in an array instead of as a single object.
import { NotionDataSource } from 'notion-api-wrapper';
const ds = new NotionDataSource(DATA_SOURCE_ID);
for await (const chunk of ds.iterator({ yieldSize: 10 })) {
const firstPage = chunk[0];
console.log(firstPage.id);
}The batchSize option controls the number of pages fetched at once from Notion. This is set to 100 by default, which is also the maximum the Notion API allows.
import { NotionDataSource } from 'notion-api-wrapper';
const ds = new NotionDataSource(DATA_SOURCE_ID);
for await (const chunk of ds.iterator({ batchSize: 10, yieldSize: 2 })) {
chunk.map((page) => console.log(page.id));
}You can also pass a custom response type to the NotionDataSource constructor. This can enable more specifc types with the cost of type safety.
import { NotionDataSource } from 'notion-api-wrapper';
type CustomType = PageObjectResponse & {
properties: { Name: { title: { plain_text: string }[] } };
};
const ds = new NotionDataSource<CustomType>(DATA_SOURCE_ID);
for await (const page of ds.iterator()) {
/* ... */
}Page Builder
The PageBuilder class that can be used to create pages in a Data Source.
import { PageBuilder } from 'notion-api-wrapper';
const builder = new PageBuilder(DATA_SOURCE_ID)
.cover('https://example.com/image.png')
.icon('🎁')
// emoji or image url:
// .icon("https://example.com/image.png")
.title('This is a Title')
.richText('Rich Text', 'Test Rich Text')
.checkbox('Checkbox', true)
.date('Date', new Date('2025-01-01'))
.files('Files & Media', 'https://example.com/image.png')
.multiSelect('Multi-Select', ['Option 1', 'Option 2'])
.number('Number', 42)
.people('People', PERSON_ID)
.phoneNumber('Phone Number', '+1 (555) 555-5555')
.relation('Relation', RELATION_PAGE)
.select('Select', 'Option A')
.status('Status', 'Done')
.url('URL', 'https://example.com');
const page = await builder.create();In addition to creating pages, PageBuilder can be used to fetch, update, and trash existing pages.
import { PageBuilder, createPage } from 'notion-api-wrapper';
const dummyPage = await createPage({
parent: {
data_source_id: DATA_SOURCE_ID,
},
properties: {},
children: [],
});
const builder = new PageBuilder(DATA_SOURCE_ID);
const existingPage = await builder.fetch(dummyPage.id);
builder.title('Updated Title');
const updatedPage = await builder.update(dummyPage.id);
const trashedPage = await builder.trash(dummyPage.id);You can seed the builder directly from a page response (e.g., from the Data Source iterator) so you only need to specify the properties you want to change. Existing properties and metadata will be preserved automatically:
import { PageBuilder } from 'notion-api-wrapper';
const builder = PageBuilder.from(existingPage);
builder.title('Updated Title');
await builder.update(existingPage.id);