Skip to main content
Custom blocks are in private alpha:
  • Do not discuss publicly or share with anyone outside your workspace.
  • Access must be enabled per workspace. Installing the SDK does not grant access.
  • These APIs may experience breaking changes without notice.
Rows come from a data source the block declared in the worker, under dataSources on worker.customBlock(). Two consequences of that shape everything below:
  • The key you declared is the key you query by. A block that declares issues calls useDataSource("issues").
  • When connected to a host, initialization validates all declared data source bindings before rendering children.
See binding a block to Notion data for how binding works, and the worker capability reference for every field of the declaration.

Query rows

useDataSource takes the key you declared and returns the bound data source’s rows.
The limit option caps how many rows the query returns. It defaults to 20 and is capped at 999. hasMore means the results are incomplete. The hook does not provide cursor pagination. You can increase limit to request a larger result set, up to the cap.

Filters and sorting

Use key to address a declared property, or propertyId to address a real Notion property ID. The SDK resolves declared keys through the block’s property mappings. filter accepts one property condition or a shallow and group with up to 25 conditions. Nested groups and or groups are unsupported. Empty checks require true. Option filters accept option names, either one string or an array. Date comparisons accept ISO 8601 dates or timestamps. Relative dates and filters on property types absent from the table are unsupported. People filters accept one explicit reference to a human user or a group. Use { object: "user", id: "..." } or { object: "group", id: "..." }. Group filters match exact group mentions. They do not expand group membership. Using bot or organization bot pointers as filter references is not supported. Creator filters require an actual Created by column in the bound database. The column can have any name. In this example, the declared property key creator maps to that column:
Use propertyId instead of key to address the column by its actual property ID. The created_by key selects the filter type. It does not identify the column. The synthetic read entry propertiesById.created_by is available without a column, but propertyId: "created_by" does not address a Created by column. Creator filters accept one explicit human user reference. Groups, bots, and organization bots are not supported as filter references. does_not_contain also matches rows with non-human or missing creators. Empty checks test whether creator metadata is missing. sorts accepts property addresses with an ascending or descending direction. Notion accepts up to 10 unique properties and applies sorts in array order. The first sort has the highest priority. See the property support table for sortable property types.

Query rows without React

Use the framework-neutral customBlock.subscribeToDataSource API. Initialize the SDK before you subscribe.
The callback receives the current snapshot and later updates. Call unsubscribe() when the view no longer needs the query:
This ends that subscription and its updates. Other subscriptions remain active.

Keys versus IDs

Every row exposes its values twice: propertiesByKey, keyed by the keys you declared in the manifest, and propertiesById, keyed by the bound data source’s real property IDs. Prefer propertiesByKey — see binding to Notion data for why.

Update a row

Each row carries its own update method, so you do not need the pages API to edit a row in a bound data source.
update resolves to a result object rather than throwing, following the same { status: "success" } or { status: "error", error } pattern as the rest of the SDK. Updates support title, rich_text, number, url, email, phone_number, checkbox, select, status, multi_select, date, people, relation, files, and place. Computed properties such as formula, rollup, and creation or edit timestamps are read-only. Declaring other property types does not make them writable. To create rows, or to work with pages outside a bound data source, use the pages API.

Archive and unarchive a row

item.archive() is shorthand for calling item.update({ is_archived: true }). item.unarchive() is shorthand for calling item.update({ is_archived: false }). Both methods return an UpdatePageResult. Use item.update to change archive status and other fields in one request.

Read the manifest at runtime

useManifest() returns the block’s declared manifest, and customBlock.getManifest() does the same outside React. Both require the block to be initialized. This is useful for rendering against your own declaration — for example, iterating declared properties to build columns — rather than hardcoding the same list in both the worker and the frontend. The init payload also carries a dataSources array describing each bound data source, including its resolved propertyIdsByKey and propertySchemasById.

Property support

This table shows property support for custom blocks running in Notion.
  • Query result shows values in propertiesById and propertiesByKey from useDataSource and customBlock.subscribeToDataSource. Missing values can be undefined.
  • Update row covers writes through item.update({ properties: ... }).
  • Filter and Sort cover query options.
  • 🟢 Supported: The SDK supports this operation in Notion.
  • 🟡 Limited: The SDK supports this operation with the restrictions shown in the cell.
  • 🔴 Unavailable: The SDK does not expose this operation.
  • ⚫ Not supported in Notion: Notion itself does not support this operation in the stated case.

Notes

  • Text values omit formatting, mention tokens, and annotations. A text fallback can be empty and does not preserve the property’s structured value. It does not provide structured formula or rollup results.
  • Record pointers contain a table name and a record ID.
  • People properties return record pointers with table values of notion_user, space_permission_group, bot, or organization_bot. Group IDs use the composite form groupId|workspaceId. People filters support users and groups. Bot and organization bot filtering is not supported.
  • Every row includes four built-in properties in propertiesById: created_time, last_edited_time, created_by, and last_edited_by. The data source does not need matching schema properties. These values are read-only. Creator filters require an actual Created by schema property even though metadata reads do not. Timestamps use NotionDateTime in UTC. Creator and editor values use arrays of record pointers.
  • The SDK accepts timestamp sorts, but the current Notion host requires a property ID in the data source’s actual schema. Sort using a configured created-time or last-edited-time property. The synthetic IDs created_time and last_edited_time alone are not sufficient.
  • You can sort by up to 10 unique properties.
  • Date-time filter values may include seconds or milliseconds, but the Notion host currently evaluates them at minute precision. Date filters do not expose relative dates or end-date targeting.
  • Status filters accept option names and empty checks, but not status groups.
  • Filters accept one condition or an and group of up to 25 conditions. The SDK does not support or or nested groups.
  • Select, multi-select, and status query values contain option names. Their schemas provide option IDs and colors separately. Writes set the selected values. They do not edit option definitions or colors.

Writing values

The value you read has a different shape from the value you write. For example, a query returns a status as a string:
To update it, wrap the string in a property object. Here, status is a declared property key:
Other write restrictions:
  • Text: Title and rich text writes preserve plain text, but not formatting or mentions.
  • Files: Supply external or existing hosted file URLs. The host stores them as links and does not support upload references.
  • Relations: Supply the complete replacement list of related pages. The host rejects has_more: true, which indicates an incomplete list.
See Pages property support for the page-property read shapes.