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

# How a block initializes

> Understand the handshake between a custom block and the Notion host.

<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 runs in a sandboxed iframe and has no direct access to the page around it. Everything it knows about Notion arrives through a handshake with the host, and everything it does to Notion goes back over the same channel.

## The handshake

Three messages establish the connection:

1. The block sends `connect` when the SDK loads.
2. The host replies with `init`, carrying the block's context.
3. The block sends `initResult` to confirm it accepted the context.

The host supplies the block ID, page, user, and data sources during initialization. The SDK exposes this as a promise, so you rarely deal with the messages directly. When connected to a host, [`NotionCustomBlock`](/custom-blocks/sdk/initialization) renders children after initialization succeeds.

When connected to a host, initialization validates all declared data source bindings. See [binding a block to Notion data](/custom-blocks/guides/data-sources) for how that works and what it means for your code.

If the host does not respond within the timeout, initialization rejects. The default is 15 seconds, which is deliberately longer than Notion's own 10-second watchdog so that a host-reported error reaches you before the SDK's generic timeout does.

## Block and app context

The SDK provides getters, subscriptions, and React hooks for block and app context.

### Getter

Getters return the current value, such as the theme, current user, or containing page. They throw if called before initialization completes.

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

await initCustomBlock()
const theme = customBlock.getTheme()
console.log(theme)
```

### Subscription

Subscriptions deliver the initial value and later changes. You can register them before initialization. They wait for initialization before delivering the initial value, or deliver immediately if initialization is complete.

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

const unsubscribe = customBlock.subscribeToTheme(theme => {
  console.log(theme)
})

await initCustomBlock()

// Call unsubscribe() when the view is removed to stop future callbacks.
```

### React hook

In React, use context hooks inside `NotionCustomBlock`. The wrapper waits for initialization, and the hooks keep components current as values change. React handles subscription cleanup when the component unmounts.

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

export function App() {
  return (
    <NotionCustomBlock>
      <ThemeLabel />
    </NotionCustomBlock>
  )
}

function ThemeLabel() {
  const theme = useTheme()
  return <p>Current theme: {theme}</p>
}
```

See [app context](/custom-blocks/sdk/app-context) for the available getters, subscriptions, and React hooks.

## When initialization fails

Initialization rejects with a `CustomBlockInitializationError`, carrying a `code` and an `isRetryable` flag alongside the message.

If you open the block directly in a browser tab, `initCustomBlock()` rejects with `NotInIframeError`.

Use the [dev shell](/custom-blocks/guides/preview) when you need realistic host behavior or data source bindings.

Other codes describe what the host could not provide: a missing or invalid manifest, an unsupported protocol version, unavailable context or user, or a data source binding that is missing, unavailable, or does not match the declared schema. See [error handling](/custom-blocks/sdk/errors) for the full contract.

## Debug console

Press `\` inside a running block to swap its UI for a log of the messages passing between the block and the host, and `\` again to go back. This is the fastest way to see why a block is stuck in its loading state. It is built into `NotionCustomBlock`, so it is only available to blocks using the React SDK. See [previewing before deploy](/custom-blocks/guides/preview).
