👉 Visit the DatoCMS homepage or see What is DatoCMS?
A lightweight, TypeScript-ready package that offers utilities to work with DatoCMS Real-time Updates API inside a browser.
npm install datocms-listen
Import subscribeToQuery from datocms-listen and use it inside your components like this:
import { subscribeToQuery } from "datocms-listen";
const unsubscribe = await subscribeToQuery({
query: `
query BlogPosts($first: IntType!) {
allBlogPosts(first: $first) {
title
nonExistingField
}
}
`,
variables: { first: 10 },
token: "YOUR_TOKEN",
includeDrafts: true,
onUpdate: (update) => {
// response is the GraphQL response
console.log(update.response.data);
},
onStatusChange: (status) => {
// status can be "connected", "connecting" or "closed"
console.log(status);
},
onChannelError: (error) => {
// error will be something like:
// {
// code: "INVALID_QUERY",
// message: "The query returned an erroneous response. Please consult the response details to understand the cause.",
// response: {
// errors: [
// {
// fields: ["query", "allBlogPosts", "nonExistingField"],
// locations: [{ column: 67, line: 1 }],
// message: "Field 'nonExistingField' doesn't exist on type 'BlogPostRecord'",
// },
// ],
// },
// }
console.error(error);
},
onError: (error) => {
// error is a MessageEvent, the actual error is in error.data
console.log(error.data);
},
onEvent: (event) => {
// event will be
// {
// status: "connecting|connected|closed",
// channelUrl: "...",
// message: "MESSAGE",
// response: Response
// }
},
});| prop | type | required | description | default |
|---|---|---|---|---|
| query | string | TypedDocumentNode |
✅ | The GraphQL query to subscribe | |
| token | string | ✅ | DatoCMS API token to use | |
| onUpdate | function | ✅ | Callback function to receive query update events | |
| onChannelError | function | ❌ | Callback function to receive channelError events | |
| onStatusChange | function | ❌ | Callback function to receive status change events | |
| onError | function | ❌ | Callback function to receive error events | |
| onEvent | function | ❌ | Callback function to receive other events | |
| variables | Object | ❌ | GraphQL variables for the query | |
| includeDrafts | boolean | ❌ | If true, draft records will be returned | |
| excludeInvalid | boolean | ❌ | If true, invalid records will be filtered out | |
| environment | string | ❌ | The name of the DatoCMS environment where to perform the query (defaults to primary environment) | |
| contentLink | 'vercel-1' or undefined |
❌ | If true, embed metadata that enable Content Link | |
| baseEditingUrl | string | ❌ | The base URL of the DatoCMS project | |
| cacheTags | boolean | ❌ | If true, receive the Cache Tags associated with the query | |
| reconnectionPeriod | number | ❌ | In case of network errors, the period (in ms) to wait to reconnect | 1000 |
| fetcher | a fetch-like function | ❌ | The fetch function to use to perform the registration query | window.fetch |
| eventSourceClass | an EventSource-like class | ❌ | The EventSource class to use to open up the SSE connection | window.EventSource |
| baseUrl | string | ❌ | The base URL to use to perform the query | https://graphql-listen.datocms.com |
This function will be called every time the channel sends an updated query result. The updateData argument has the following properties:
| prop | type | description |
|---|---|---|
| response | Object | The GraphQL updated response |
The status argument represents the state of the server-sent events connection. It can be one of the following:
connecting: the subscription channel is trying to connectconnected: the channel is open, we're receiving live updatesclosed: the channel has been permanently closed due to a fatal error (i.e. an invalid query)
The errorData argument has the following properties:
| prop | type | description |
|---|---|---|
| code | string | The code of the error (i.e. INVALID_QUERY) |
| message | string | A human-friendly message explaining the error |
| fatal | boolean | If true, the channel has been closed and will not reconnect |
| response | Object | The raw response returned by the endpoint, if available (optional) |
This function is called when connection errors occur (network errors, SSE errors).
The error argument is a standard MessageEvent. The actual error object is available in error.data.
This function is called when other events occur.
The event argument has the following properties:
| prop | type | description |
|---|---|---|
| status | string | The current connection status (see above) |
| channelUrl | string | The current channel URL |
| message | string | A human-friendly message explaining the event |
| response | Response | The HTTP response from the registration request |
The function returns a Promise<() => void>. You can call the function to gracefully close the SSE channel.
Every user-visible change needs a changeset: run npx changeset from the repo
root in the same PR, pick the bump level (patch is for bug fixes only, new API
surface is minor) and commit the file it writes under .changeset/. That is
where the changelog entry comes from, and it is where the bump level is decided
— not on release day. See .changeset/README.md.
To release, from an up-to-date, clean main, run npm run release. It
builds and tests, applies the pending changesets — bumping the version and
writing CHANGELOG.md — publishes to npm, and only then tags vX.Y.Z, pushes,
and creates a GitHub release whose notes come straight from that changelog
entry. An interrupted release is resumed by re-running it, never undone. Use
npm run release:next for a prerelease under the next dist-tag.
The script is
@datocms/release-toolchain,
shared with every other DatoCMS repository and pinned here by tag.
Every push to a branch here publishes a preview of the package, which you can
install anywhere — no npm release, no npm link:
npm i https://pkg.pr.new/datocms/datocms-listen@<commit-sha>
The exact URL shows up in the commit's check run on GitHub, and in a comment on the pull request once there is one. This is the supported way to try a change inside a site that lives in another repository, or to hand a fix to whoever reported it before it is released.
Previews are throwaway: they are never published to npm, and the URL stops
resolving after a while. Never commit one to a package.json that ships.
DatoCMS is Headless CMS for the modern web. Trusted by 25,000+ businesses, agencies, and individuals, it gives your team one place to manage content and ship it to any website, app, or device via API.
New here? Start with Create free account and the Documentation. Stuck? Ask the Community. Curious what's new? Product Updates.
Building with AI: Agent Skills turn coding assistants (Claude Code, Cursor) into expert DatoCMS developers, with full read/write via the auto-installed CLI. No local terminal? Use the MCP Server instead.
Talking to DatoCMS from code:
- Content Delivery API (CDA) — the fast, read-only GraphQL API your website/app uses to fetch published content.
- Content Management API (CMA) — the REST API for creating and updating content, models, and project settings (think scripts, migrations, integrations).
- CLI — terminal tool for schema migrations and importing from Contentful/WordPress.
Framework guides: end-to-end recipes for fetching content, rendering Structured Text, optimizing images/video, handling SEO, and setting up live preview with visual editing in Next.js, Nuxt, Svelte, and Astro.
Want a head start? Browse our starter projects — ready-to-deploy example sites for popular frameworks.