Official Notion JavaScript Client
A JavaScript and TypeScript client for the Notion API. This reference covers the SDK's methods, options, and helpers.
npm install @notionhq/client
[!NOTE] For setup steps, see Notion's getting started guide.
Client accepts an integration token or an OAuth access token.
const { Client } = require("@notionhq/client")
const notion = new Client({
auth: process.env.NOTION_TOKEN,
})
Make a request to any Notion API endpoint.
;(async () => {
const listUsersResponse = await notion.users.list({})
console.log(listUsersResponse)
})()
[!NOTE] See the complete list of endpoints in the API reference.
Request methods return a Promise with the response. For example:
{
results: [
{
object: "user",
id: "d40e767c-d7af-4b18-a86d-55c61f1e39a4",
type: "person",
person: {
email: "[email protected]",
},
name: "Avocado Lovelace",
avatar_url:
"https://secure.notion-static.com/e6a352a8-8381-44d0-a1dc-9ed80e62b53d.jpg",
},
// ...
]
}
Endpoint parameters are grouped into a single object. You don't need to remember which parameters go in the path, query, or body.
const myPage = await notion.dataSources.query({
data_source_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
filter: {
property: "Landmark",
rich_text: {
contains: "Bridge",
},
},
})
Notion API errors reject the request with an APIResponseError. The code property identifies the error. APIErrorCode contains the known server error codes.
…
The default logger writes warnings and errors to the console. LogLevel.DEBUG also logs response bodies.
const { Client, LogLevel } = require("@notionhq/client")
const notion = new Client({
auth: process.env.NOTION_TOKEN,
logLevel: LogLevel.DEBUG,
})
A custom logger receives logLevel, message, and extraInfo. It should return no value.
The Client constructor accepts one options object.
| Option | Default value | Type | Description |
|---|---|---|---|
auth |
undefined |
string |
Bearer token for authentication. If left undefined, the auth parameter should be set on each request. |
logLevel |
LogLevel.WARN |
LogLevel |
Verbosity of logs the instance will produce. By default, logs are written to stdout. |
timeoutMs |
DEFAULT_TIMEOUT_MS |
number |
Number of milliseconds to wait before emitting a RequestTimeoutError |
baseUrl |
DEFAULT_BASE_URL |
string |
The root URL for sending API requests. This can be changed to test with a mock server. |
logger |
Log to console | Logger |
A custom logging function. This function is only called when the client emits a log that is equal or greater severity than logLevel. |
agent |
Default node agent | http.Agent |
Used to control creation of TCP sockets. A common use is to proxy requests with https-proxy-agent |
retry |
See constants | RetryOptions |
Configuration for automatic retries on rate limits (429), service overloads (529), and server errors (500, 503). See Automatic retries below. |
The client retries failed requests up to 2 times by default. Delays increase with each retry and include a random offset.
Retried errors:
rate_limited (HTTP 429) - Too many requests; retried for all HTTP methodsservice_overload (HTTP 529) - Service overloaded; retried for all HTTP methodsinternal_server_error (HTTP 500) - Server error; retried only for GET and DELETEservice_unavailable (HTTP 503) - Service temporarily unavailable; retried only for GET and DELETEFor server errors, only GET and DELETE are retried to avoid repeating writes. The client uses the Retry-After header when present. It accepts a delay in seconds or an HTTP date.
Retry options:
const notion = new Client({
auth: process.env.NOTION_TOKEN,
retry: {
maxRetries: 5, // Maximum retry attempts (default: 2)
initialRetryDelayMs: 500, // Initial delay between retries (default: 1000ms)
maxRetryDelayMs: 60000, // Maximum delay between retries (default: 60000ms)
},
})
To disable automatic retries:
const notion = new Client({
auth: process.env.NOTION_TOKEN,
retry: false,
})
The SDK exports these defaults and Notion-specific values:
const {
DEFAULT_BASE_URL, // "https://api.notion.com"
DEFAULT_TIMEOUT_MS, // 60_000
DEFAULT_MAX_RETRIES, // 2
DEFAULT_INITIAL_RETRY_DELAY_MS, // 1_000
DEFAULT_MAX_RETRY_DELAY_MS, // 60_000
MIN_VIEW_COLUMN_WIDTH, // 32
} = require("@notionhq/client")
MIN_VIEW_COLUMN_WIDTH is the minimum table column width in pixels. A column at this width appears collapsed. For example:
await notion.views.create({
database_id: databaseId,
name: "My view",
type: "table",
configuration: {
table: {
properties: [
{
property_id: checkboxPropId,
visible: true,
width: MIN_VIEW_COLUMN_WIDTH,
},
],
},
},
})
The package includes types for request parameters, responses, and their fields.
With strict TypeScript, caught errors have type unknown. isNotionClientError
narrows the error to a known SDK error type. APIErrorCode identifies server
errors; ClientErrorCode identifies errors raised by the client.
…
These type guards distinguish full API responses from partial responses.
| Type guard function | Purpose |
|---|---|
isFullPage |
Determine whether an object is a full PageObjectResponse |
isFullBlock |
Determine whether an object is a full BlockObjectResponse |
isFullDataSource |
Determine whether an object is a full DataSourceObjectResponse |
isFullPageOrDataSource |
Determine whether an object is a full PageObjectResponse or DataSourceObjectResponse |
isFullUser |
Determine whether an object is a full UserObjectResponse |
isFullComment |
Determine whether an object is a full CommentObjectResponse |
Example:
const fullOrPartialPages = await notion.dataSources.query({
data_source_id: "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
})
for (const page of fullOrPartialPages.results) {
if (!isFullPageOrDataSource(page)) {
continue
}
// The page variable has been narrowed from
// PageObjectResponse | PartialPageObjectResponse | DataSourceObjectResponse | PartialDataSourceObjectResponse
// to
// PageObjectResponse | DataSourceObjectResponse.
console.log("Created at:", page.created_time)
}
These helpers read results across multiple pages.
iteratePaginatedAPI(listFn, firstPageArgs)Returns an async iterator that reads each page of results as needed.
Parameters:
listFn: Any function on the Notion client that represents a paginated API (i.e. accepts
start_cursor.) Example: notion.blocks.children.list.firstPageArgs: Arguments that should be passed to the API on the first and subsequent calls
to the API, for example a block_id.Returns:
An async iterator over results from the API.
Example:
for await (const block of iteratePaginatedAPI(notion.blocks.children.list, {
block_id: parentBlockId,
})) {
// Do something with block.
}
collectPaginatedAPI(listFn, firstPageArgs)Accepts the same arguments as iteratePaginatedAPI and returns all results in
one array. The results must fit in memory.
Parameters:
listFn: Any function on the Notion client that represents a paginated API (i.e. accepts
start_cursor.) Example: notion.blocks.children.list.firstPageArgs: Arguments that should be passed to the API on the first and subsequent calls
to the API, for example a block_id.Returns:
An array with results from the API.
Example:
const blocks = await collectPaginatedAPI(notion.blocks.children.list, {
block_id: parentBlockId,
})
// Do something with blocks.
iterateAllDataSourceRows(client, args)Reads rows beyond the limit for a single data source query, which is 10,000 by
default. At that limit, has_more is false and request_status.type is
"incomplete"; ordinary pagination stops.
This helper sorts by created_time and starts a new query from the last row's
timestamp each time it reaches the limit. It removes duplicate rows by ID.
Parameters:
client: A Notion client instance.args: The same arguments as dataSources.query, minus the fields the helper
controls: start_cursor (pagination is automatic) and sorts (set to
created_time ascending to partition). data_source_id is required. Any
filter you pass is combined with the window bound using and.Returns:
An async iterator over every row in the data source.
Throws:
If a single created_time value holds more rows than the limit, the window
cannot be narrowed by time alone. Pass a filter in that case so each window
stays under the limit.
Example:
for await (const row of iterateAllDataSourceRows(notion, {
data_source_id: dataSourceId,
})) {
// Do something with row.
}
collectAllDataSourceRows(client, args)Accepts the same arguments as iterateAllDataSourceRows and returns all results
in one array. The full data source must fit in memory. For larger data sources,
iterateAllDataSourceRows reads rows as a stream.
Parameters:
client: A Notion client instance.args: The same arguments as iterateAllDataSourceRows.Returns:
An array with every row in the data source.
Example:
const rows = await collectAllDataSourceRows(notion, {
data_source_id: dataSourceId,
})
// Do something with rows.
request() calls a Notion API endpoint directly. For example:
// POST /v1/comments
const response = await notion.request({
path: "comments",
method: "post",
body: {
parent: { page_id: "5c6a28216bb14a7eb6e1c50111515c3d" },
rich_text: [{ text: { content: "Hello, world!" } }],
},
// No `query` params in this example, only `body`.
})
console.log(JSON.stringify(response, null, 2))
notion.request<ResponseBody>({...}) uses `ResponseB
No open issues yet, or sync has not completed.