> ## Documentation Index
> Fetch the complete documentation index at: https://developers.notion.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Initialization

> Connect a custom block to the Notion host and render once it is ready.

<Warning>
  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.
</Warning>

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](/custom-blocks/guides/lifecycle).

## `NotionCustomBlock`

`NotionCustomBlock` runs the handshake. It renders its children after initialization succeeds. Wrap your application in `NotionCustomBlock`.

```tsx theme={null}
import "@notionhq/custom-blocks/nds.css"
import {
	NotionCustomBlock,
	NotionTokenScope,
} from "@notionhq/custom-blocks/react"

ReactDOM.createRoot(root).render(
	<NotionCustomBlock>
		<NotionTokenScope>
			<App />
		</NotionTokenScope>
	</NotionCustomBlock>,
)
```

| Prop | Description |
| - | - |
| `children` | The content to render after initialization. See the `NotInIframeError` exception below. |
| `fallback` | Rendered while initialization is in flight. Defaults to `null`. |
| `errorFallback` | A node or function that renders an initialization error. See the `NotInIframeError` exception below. |
| `timeoutMs` | How long to wait for the host's `init` response. Defaults to `15000`. |

`NotionTokenScope`, contrast mode, and sizing are covered in [appearance and sizing](/custom-blocks/sdk/appearance).

`NotionCustomBlock` handles `NotInIframeError` separately. See [error handling](/custom-blocks/sdk/errors#notiniframeerror) 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`.

```tsx theme={null}
import { useCustomBlockInit } from "@notionhq/custom-blocks/react"

function Boot() {
	const init = useCustomBlockInit()

	if (init.error) return <Failed error={init.error} />
	if (!init.isLoaded) return <Spinner />

	return <App user={init.initial.currentUser} />
}
```

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.

```typescript theme={null}
import { customBlock, initCustomBlock } from "@notionhq/custom-blocks"

const context = await initCustomBlock()
// context.blockId, context.page, context.currentUser,
// context.theme, context.contrastMode, context.parent, context.dataSources
```

After it resolves, read context from the `customBlock` object — see [app context](/custom-blocks/sdk/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](/custom-blocks/sdk/errors) for the full set of codes.
