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.
A custom block receives real context through a handshake with the host. These are the APIs that run that handshake and let you render loading and error states around it. For what the handshake does and why, see how a block initializes.

NotionCustomBlock

NotionCustomBlock runs the handshake. It renders its children after initialization succeeds. Wrap your application in NotionCustomBlock.
NotionTokenScope, contrast mode, and sizing are covered in appearance and sizing. NotionCustomBlock handles NotInIframeError separately. See error handling for this exception.

useCustomBlockInit

The one hook safe to call before initialization. Use it when you need to render your own loading and error states outside NotionCustomBlock.
The result is a discriminated union: { isLoaded: false, error: undefined } while in flight, { isLoaded: false, error } on failure, and { isLoaded: true, error: undefined, initial } on success, where initial is the full init payload. Every other hook must be called inside NotionCustomBlock, because they throw if the block is not yet initialized.

initCustomBlock

Outside React, initCustomBlock() performs the handshake and resolves with the block’s context. Calling it more than once returns the same promise.
After it resolves, read context from the customBlock object — see app context. Await initCustomBlock() before calling context getters. Context subscriptions can be registered earlier and wait for initialization before delivering the initial value.

Initialization errors

initCustomBlock() and useCustomBlockInit() report initialization failures as a CustomBlockInitializationError. This error contains code, message, and isRetryable. See error handling for the full set of codes.