Sanity uses a project-based access model where users are invited to individual projects with assigned roles. The permission system has two tiers: built-in roles available on all plans, and a custom access control system (using GROQ filters) available on Enterprise plans. API tokens are managed separately from user roles and can be scoped to specific datasets.
Permission model
Sanity's access control works at three levels:
- Organization membership -- users belong to an organization and can be granted access to one or more projects within it. Organization-level admins can manage billing and project creation.
- Project roles -- each user gets a role per project. Roles define what operations (read, create, update, delete, publish) the user can perform on documents. Roles apply across all datasets in the project unless custom access control is used.
- Custom Access Control (Enterprise) -- define granular rules using GROQ filters that restrict access based on document type, field values, or user attributes. Rules can scope permissions to specific datasets, document types, or even individual documents.
Sanity's content model is document-based. Permissions apply to documents as a whole; there are no field-level read/write restrictions in the built-in role system (though custom access control can approximate this).
Built-in roles
| Role | Permissions | Notes |
|---|---|---|
| Administrator | Full project access: manage members, datasets, CORS origins, tokens, API settings, all document operations | Cannot manage organization billing unless also org admin |
| Editor | Create, read, update, delete, publish documents across all datasets | No project settings, member management, or token creation |
| Viewer | Read-only access to all documents across all datasets | Cannot create, edit, delete, or publish. Can use Studio in read-only mode |
| Deploy Studio | Deploy Sanity Studio instances | Typically granted alongside another role; only controls deployment |
| Custom roles (Enterprise) | Configurable per document type and dataset | Defined in project settings or via management API |
Roles are assigned per project. A user can be an Administrator on Project A and a Viewer on Project B.
Admin UI paths
| Task | Location |
|---|---|
| Manage project members | sanity.io/manage > [Project] > Members |
| Invite users | Members > Invite member (email + role) |
| Change roles | Members > [User] > Change role |
| API tokens | sanity.io/manage > [Project] > API > Tokens |
| CORS origins | sanity.io/manage > [Project] > API > CORS Origins |
| Datasets | sanity.io/manage > [Project] > Datasets |
| Organization members | sanity.io/manage > [Organization] > Members |
| Custom access control | sanity.io/manage > [Project] > Access (Enterprise) |
| Usage/billing | sanity.io/manage > [Organization] > Usage |
API access management
API tokens:
- Created at Project > API > Tokens
- Three permission levels: Viewer (read-only GROQ/GraphQL), Editor (read + write), Deploy Studio (deploy only)
- Tokens are project-scoped and apply to all datasets
- No expiration date; rotate manually by deleting and recreating
- Used as Bearer tokens in API requests:
Authorization: Bearer <token>
Content Lake API:
- GROQ queries at
https://<project-id>.api.sanity.io/v2024-01-01/data/query/<dataset> - Mutations at
https://<project-id>.api.sanity.io/v2024-01-01/data/mutate/<dataset> - Token permission level controls which operations succeed
Webhooks:
- Configured at Project > API > Webhooks
- Trigger on document create/update/delete/publish events
- Filter by document type or GROQ projection
- Include a secret for HMAC signature verification
- Each webhook has its own dataset scope
CORS origins:
- Control which domains can make browser-based API requests
- Essential for Sanity Studio deployments and client-side queries
- Manage at Project > API > CORS Origins
- Add
allow credentialsfor authenticated browser requests
Analytics-specific permissions
Sanity is a headless CMS, so analytics lives in your frontend. Sanity's role in analytics governance:
- Tracking configuration documents -- store analytics settings (GA ID, GTM container, pixel IDs) as a Sanity document type. Editors can modify these; restrict to Administrators for production safety using custom access control on Enterprise, or use a dedicated dataset with limited editor access.
- Content analytics fields -- if documents include UTM parameters, campaign tags, or A/B test variant fields, all Editors can modify them. Consider a publishing workflow where changes to analytics fields require Administrator approval.
- GROQ-powered analytics queries -- use Viewer tokens to query content metadata for analytics pipelines (page views by content type, publish frequency, content freshness). Create a dedicated "Analytics Pipeline" token at Viewer level.
- Sanity Studio plugins -- dashboard plugins like
@sanity/dashboardcan embed analytics widgets. Studio plugin access is controlled by deployment, not per-user roles -- all Studio users see the same plugins. - Document history -- Sanity tracks full revision history on all documents. Use the History API to audit who changed analytics-related fields. Query at
/data/history/<dataset>with a token.
For analytics teams that only need to read content data for reporting, assign the Viewer role and create a dedicated Viewer API token. This prevents any accidental content modifications while allowing full read access to the Content Lake.
Sub-pages
- Roles and Permissions -- custom access control with GROQ filters, dataset-scoped permissions, and role assignment patterns
- Adding and Removing Users -- inviting members, managing API tokens, and offboarding from projects and organizations