Collaboration (Beta)

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.

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.

Beta

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

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.

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

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

Replace with your project ID from 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.

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.

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.

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.

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.

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). 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.
  • 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 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 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.

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 and @sanity/sdk-react. The props of the @sanity/collaboration/sdk components are in Storybook: Providers for SDKCommentsProvider, CommentsPanel for the props SDKCommentsPanel passes through, Hooks for useSDKThreadCallbacks, and Portable Text for SDKPortableTextComments.

Was this page helpful?

Sanity logosanity.ioAll Systems Operational© Sanity 2026
Change site theme