> For AI agents: the complete Sanity documentation index is available at [https://www.sanity.io/docs/llms.txt](https://www.sanity.io/docs/llms.txt).

# Comments in the App SDK

Read and write Sanity comments with the App SDK collaboration API: documents, fields, threads and live lists.

The Sanity App SDK reads and writes comments on your documents. A comment belongs to a document, and optionally to one field of it. Comments sharing a `threadId` form a thread, and every list is live: a comment written elsewhere appears in your app without a refetch.

With the collaboration API, you can:

- **Read a document's threads live**, grouped and kept current as new comments arrive.
- **Query comments across documents**, such as every open thread that mentions the current user.
- **Write, reply to, edit, and resolve comments**, with optimistic updates and a retry path for a failed create.
- **Anchor a comment to a run of text** in a Portable Text field.
- **Use it outside React**, from a script, a server, or another framework.

[Read comments](https://www.sanity.io/docs/collaboration/sdk-read-comments)
Read a document's threads, live.

[Write comments](https://www.sanity.io/docs/collaboration/sdk-write-comments)
Start threads, reply, edit, and resolve.

These guides cover that API task by task: reading a document's comments, querying across an organization, writing, anchoring, and using it outside React. The `@sanity/collaboration` components render what it returns, and `@sanity/collaboration/sdk` wires the two together.

> [!WARNING]
> Beta
> Everything on these pages is marked `@beta` in the SDK. It ships in `@sanity/sdk` and `@sanity/sdk-react` 3.11.0 and later, and its shape can still change in a later release.

## Import paths

| Import path | What it holds | Use it when |
| --- | --- | --- |
| `@sanity/sdk-react/collaboration` | The React hooks, plus everything from `@sanity/sdk/collaboration`, re-exported | You are in React. This is the one most apps need. |
| `@sanity/sdk/collaboration` | The framework-agnostic half: actions, read state, `buildCommentThreads`, and the types | You are outside React: a script, a server, another framework. |
| `@sanity/collaboration/sdk` | Our components wired to the hooks: `SDKCommentsProvider`, `SDKCommentsPanel` and the rest | You want the components to do the reading and writing. |

`@sanity/sdk-react/collaboration` re-exports the whole of `@sanity/sdk/collaboration`, so a React app imports types, actions and `buildCommentThreads` from the same place as the hooks.

### Why a `/collaboration` subpath

The package roots, `@sanity/sdk` and `@sanity/sdk-react`, still carry the older comment hooks that read the add-on comments dataset. Those are deprecated, and they have the same names as the ones here: `useComments`, `useCommentThreads`, `CommentsOptions` and so on. The subpath is what lets both ship side by side.

In the next major the deprecated ones go away and these move to the package roots. `/collaboration` keeps re-exporting them through that major, marked `@deprecated`, and is removed in the major after.

Moving off the deprecated hooks keeps the same names but changes a little more than the import path:

- `createComment` takes `anchor` instead of `selection` to attach a comment to a run of text. Code that passes `selection` stops compiling.
- Reads take a `scope`, which defaults to `'perspective'`: while a release is in view you get that release's comments, not draft and published pooled together. See [Drafts, published and releases](https://www.sanity.io/docs/collaboration/sdk-read-comments).
- Read results gain an `error` field, set when a list that has already loaded stops following the server.
- Comments use the organization that owns the project, and an organization named by the Dashboard or the config has to match it. See [Which organization](https://www.sanity.io/docs/collaboration/sdk-overview).

## Setup

### App setup

The hooks read their instance from `SanityApp`, or from `SDKProvider` if you assemble the providers yourself. Nothing extra is needed for comments: a config with a project and a dataset is enough.

```tsx
import {AuthBoundary, SanityApp} from '@sanity/sdk-react'

export function App() {
  return (
    <SanityApp
      config={{projectId: 'YOUR_PROJECT_ID', dataset: 'production'}}
      fallback={<p>Starting…</p>}
    >
      <AuthBoundary>{/* your app */}</AuthBoundary>
    </SanityApp>
  )
}
```

Replace `YOUR_PROJECT_ID` with your project ID from [sanity.io/manage](https://www.sanity.io/manage).

Reading needs read access to the dataset a comment belongs to. Access is decided per dataset, not per document, so a role whose filter hides a document can still read that document's comments. Writing needs a signed-in user, since the server records the author: a write without one throws `Writing a comment requires a logged in user.`

### Which organization

Comments are stored per organization and reached through the collaboration API. Sanity Studio comments before Comments API v2 were stored per dataset. You don't configure which organization: comments use the organization that owns the project you're reading.

If the app also names an organization, the SDK checks it against the project's organization, and a mismatch is an error rather than a silent read from another organization. Inside the Sanity Dashboard, that's the organization the app was opened in. Outside it, that's `organizationId` on the config, if you set it.

`organizationId` is for standalone apps that read other organization-scoped data, such as organization user lists. Comments don't need it. It's unrelated to `auth.oauth.organizationId`, which restricts the tokens the OAuth flow issues.

### Document handles

The reads that cover one document take a document handle: a `documentId` and a `documentType`, plus the optional `projectId`, `dataset`, `perspective` and `resource` every SDK handle carries. Leave those out and they come from the surrounding `SanityApp` or `ResourceProvider`.

```typescript
const handle = {documentId: 'post-123', documentType: 'post'}
```

A comment always belongs to the published id. `documentId` can be a published, draft or version id; the comments come back with `documentId` set to the published id and `sourceDocumentId` set to the exact id each was written against. Which forms of a document a read covers is the `scope` option, covered in [Drafts, published and releases](https://www.sanity.io/docs/collaboration/sdk-read-comments).

Reads key on the handle's fields, so a fresh object on each render is fine. `useSDKThreadCallbacks` is different: its callbacks follow the handle's identity, so memoize the handle you pass it.

### Resources and perspectives

An app can read from more than one project or dataset. The comment hooks take the resource the way every SDK hook does: pass `resource` or `resourceName` on the options, or leave both out and the surrounding `ResourceProvider` decides.

```tsx
const {threads} = useCommentThreads({
  resourceName: 'secondary',
  documentId,
  documentType: 'article',
})
```

For a document read the resource picks the organization and the document; for a query it picks only the organization. See [Scope to one dataset](https://www.sanity.io/docs/collaboration/sdk-query-comments).

`useCommentActions` resolves the resource, and the organization, when an action is called, not when the hook runs, so one set of callbacks works across several resources. Pass `resource` or `resourceName` on the call, or leave them out and the `ResourceProvider` around the hook decides. The organization cannot be passed on the call; it follows [Which organization](https://www.sanity.io/docs/collaboration/sdk-overview).

`perspective` works the same way: per call, or from the surrounding provider. For reads it decides which forms of a document the comments come from (see [Drafts, published and releases](https://www.sanity.io/docs/collaboration/sdk-read-comments)). For `createComment`, a release perspective writes the comment against the release's version of the document, so it belongs to that release; any other perspective writes against the `documentId` as given.

## Which layer to use

The SDK and the components are separate layers, and you can take either without the other.

- **Use @sanity/collaboration/sdk** when the default panel or inline comments fit. `SDKCommentsPanel` reads the threads and wires every write for you. See [SDK-wired comment components](https://www.sanity.io/docs/collaboration/sdk-components).
- **Use the components with the hooks** when the arrangement is yours: your own list layout, a write that needs confirming, or comments shown somewhere the panel is not. Read with `useCommentThreads`, pass the threads to `CommentList`, and wire the writes, with `useSDKThreadCallbacks` doing most of it. [Comment data flow](https://www.sanity.io/docs/collaboration/data-flow) covers the shape.
- **Use the SDK directly** when the UI is entirely your own, or when there is no UI at all: a badge counting open threads, a notification feed, a script that resolves stale threads. The hooks and actions on these pages are the whole of it.

[Levels of abstraction in the comment stack](https://www.sanity.io/docs/collaboration/levels-of-abstraction) lays out every rung, down to the client and raw HTTP.

For how `@sanity/collaboration/sdk` maps onto these hooks, see [SDK-wired comment components](https://www.sanity.io/docs/collaboration/sdk-components).

## Reference

These pages show the calls each task needs, not every signature. For the full signatures, options and types of the hooks and actions, see the SDK's generated reference for [@sanity/sdk](https://reference.sanity.io/_sanity/sdk/) and [@sanity/sdk-react](https://reference.sanity.io/_sanity/sdk-react/). The props of the `@sanity/collaboration/sdk` components are in Storybook: [Providers](https://collaboration-platform.sanity.dev/?path=/docs/default-providers--docs) for `SDKCommentsProvider`, [CommentsPanel](https://collaboration-platform.sanity.dev/?path=/docs/default-commentspanel--docs) for the props `SDKCommentsPanel` passes through, [Hooks](https://collaboration-platform.sanity.dev/?path=/docs/hooks--docs) for `useSDKThreadCallbacks`, and [Portable Text](https://collaboration-platform.sanity.dev/?path=/docs/portable-text--docs) for `SDKPortableTextComments`.

