npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

notion-api-wrapper

v6.0.0

Published

Zero dependency Notion API client

Downloads

227

Readme

Notion API Wrapper

Zero dependency Notion API client.

Installation

npm install notion-api-wrapper

Or 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.

  1. Create new integration at https://www.notion.so/profile/integrations. You can revoke the Notion API token at any time in the same URL.

  2. 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>.

  3. 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 the notionToken option.

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-wrapper

You 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-database

The 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);