SDK: Client Library

The @dotcms/client is a powerful JavaScript/TypeScript SDK designed to simplify the integration of dotCMS content into your applications. Whether building dynamic websites or content-driven apps, this SDK offers an intuitive API for seamless and type-safe content retrieval, enabling you to create engaging experiences effortlessly by accessing and displaying content from dotCMS.

When to Use It:#

  • Building headless frontends that need dotCMS content
  • Building content-driven apps that need to access dotCMS content
  • Developing multi-language or personalized experiences
  • Implementing dynamic navigation and page structures

Key Benefits:#

  • Simplified Development: Write less code with intuitive methods and builders
  • Type Safety: Built-in TypeScript definitions prevent runtime errors
  • Universal Compatibility: Works in both browser and Node.js environments
  • Security First: Handles authentication and requests securely
  • Developer Experience: Rich autocompletion and documentation

Prerequisites & Setup#


Get a dotCMS Environment#

Version Compatibility#

  • Recommended: dotCMS Evergreen
  • Minimum: dotCMS v25.05
  • Best Experience: Latest Evergreen release

Environment Setup#

For Production Use:

For Testing & Development:

For Local Development:

Create a dotCMS API Key#

[!TIP] Make sure your API Token has read-only permissions for Pages, Folders, Assets, and Content. Using a key with minimal permissions follows security best practices.

This integration requires an API Key with read-only permissions for security best practices:

  1. Go to the dotCMS admin panel.
  2. Click on System > Users.
  3. Select the user you want to create the API Key for.
  4. Go to API Access Key and generate a new key.

For detailed instructions, please refer to the dotCMS API Documentation - Read-only token.

Installation#

Install the SDK and required dependencies:

npm install @dotcms/client@next @dotcms/types@next

[!TIP] If you are working with pure JavaScript, you can avoid installing the @dotcms/types package.

Quickstart: Basic Setup Example#


Here's a basic setup of the dotCMS Client SDK to help you get started:

import { createDotCMSClient } from '@dotcms/client/next';

// Create a client instance
const client = createDotCMSClient({
    dotcmsUrl: 'https://your-dotcms-instance.com',
    authToken: 'your-auth-token', // Optional for public content
    siteId: 'your-site-id' // Optional site identifier
});

// Start using the client!
const { pageAsset } = await client.page.get('/about-us');
console.log(pageAsset.page.title);

Full-Stack Example Projects Using the SDK#

While there isn't a dedicated example project specifically for the client SDK, you can see it in action within these full-stack examples:

These examples demonstrate how to use the client SDK as part of a complete web application.

Key Concepts#


TermDescriptionDocumentation
pageAssetThe page data structure containing layout and contentPage API
contentletA single piece of content in dotCMSContent API
collectionA group of contentlets of the same typeContent API
graphqlQuery language used to extend API responsesGraphQL

Choosing the Right Method#


The dotCMS Client SDK provides three core methods for fetching data. Use this quick guide to decide which one is best for your use case:

MethodUse When You Need...Best For
client.page.get()A full page with layout, containers, and related contentRendering entire pages with a single request. Ideal for headless setups, SSR/SSG frameworks, and cases where you want everything—page structure, content, and navigation—tied to a URL path.
client.content.getCollection()A filtered list of content items from a specific content typePopulating dynamic blocks, lists, search results, widgets, or reusable components.
client.navigation.get()Only the site's navigation structure (folders and links)Standalone menus or use cases where navigation is needed outside of page context.

Start with page.get(): The One-Request Solution#

For most use cases, client.page.get() is all you need. It lets you retrieve:

  • The full page layout
  • Related content
  • Navigation structure

All in a single request using GraphQL.

Only use content.getCollection() or navigation.get() if you have advanced needs, like real-time data fetching or building custom dynamic components.

🔍 For an example of how to bundle content and navigation in one page.get() call, see the advanced usage section under client.page.get().

API Reference#


createDotCMSClient: Client Initialization#

The createDotCMSClient function is the first step in using the dotCMS Client SDK. It allows you to create a new client instance with your dotCMS configuration.

OptionTypeRequiredDescription
dotcmsUrlstringYour dotCMS instance URL
authTokenstringAuthentication token
siteIdstringSite identifier (falls back to default site if not specified)
requestOptionsRequestOptionsAdditional fetch options

Initialization Example#

import { createDotCMSClient } from '@dotcms/client/next';

const client = createDotCMSClient({
    dotcmsUrl: 'https://your-dotcms-instance.com',
    authToken: 'your-auth-token',
    siteId: 'your-site-id',
    requestOptions: {
        headers: { 'Custom-Header': 'value' },
        cache: 'default'
    }
});

client.page.get(): Fetching Page Content#

The client.page.get() method is your primary way to retrieve page content from dotCMS using the SDK. It abstracts away the complexity of raw REST or GraphQL calls, letting you fetch structured page data with just a single method.

Why Use page.get()?#

  • Fetch everything needed to render a page with one call
  • Avoid building multiple API queries manually
  • Type-safe, customizable, and extensible with GraphQL
  • Works with dotCMS content localization and personalization out of the box

Basic Usage#

Here's the simplest way to fetch a page by its URL:

const { pageAsset } = await client.page.get('/about-us');
console.log(pageAsset.page.title);

You can now render this content or pass it to your components.

Customizing the Request#

You can customize the request to fetch different languages, rendering modes, or user personas:

const { pageAsset } = await client.page.get('/about-us', {
    languageId: '2',
    fireRules: true,
    personaId: '1234'
});

Bundling Content and Navigation in One Request#

You can also pull in related content, like blog posts or navigation menus, using the graphql option:

const { pageAsset, content } = await client.page.get('/about-us', {
    graphql: {
        page: `
            title
            vanityUrl {
                url
            }
        `,
        content: {
            blogPosts: `
                BlogCollection(limit: 3) {
                    title
                    urlTitle
                }
            `,
            navigation: `
                DotNavigation(uri: "/", depth: 2) {
                    href
                    title
                    children {
                        href
                        title
                    }
                }
            `
        }
    }
});

Request Options#

The page.get() method accepts an optional second argument of type DotCMSPageRequestParams. This lets you customize how the page is fetched. Common options include:

OptionTypeDescription
languageIdstring | numberLanguage version of the page
modestringRendering mode: LIVE, PREVIEW_MODE, etc.
personaIdstringPersonalize content based on persona ID
graphqlDotCMSGraphQLParamsGraphQL options for extending the response
fireRulesbooleanWhether to trigger page rules

The graphql option allows you to customize the page and content data returned. It accepts:

PropertyTypeDescription
pagestringGraphQL partial query that will be automatically wrapped with the page context. (you don't need to include the page(url:"/") wrapper in your query)
contentobjectNamed queries to fetch additional content
fragmentsstring[]GraphQL fragments that can be reused across queries
variablesobjectVariables to pass into the GraphQL queries

💡 See DotCMSPageRequestParams for a full list of supported options.

Method Signature#

get<T extends DotCMSExtendedPageResponse = DotCMSPageResponse>(
  url: string,
  options?: DotCMSPageRequestParams
): Promise<DotCMSComposedPageResponse<T>>;

client.navigation.get(): Fetching Navigation Structure#

The client.navigation.get() method fetches a structured view of a site's file and folder hierarchy from dotCMS. It's useful for building menus and navigation UIs.

Basic Usage#

Here's the simplest way to fetch the root-level navigation:

const nav = await client.navigation.get('/');
console.log(nav);

Customizing the Request#

You can tailor the navigation structure using optional parameters:

const nav = await client.navigation.get('/', {
    depth: 2,
    languageId: 1
});

Request Options#

The navigation.get() method accepts an optional second argument with the following parameters:

OptionTypeDescription
depthnumberNumber of child levels to include
languageIdnumberLanguage ID for localized navigation names

💡 For typical use cases, setting depth: 2 will include top-level navigation and one level of children.

Method Signature#

get(
  uri: string,
  options?: {
    depth?: number;
    languageId?: number;
  }
): Promise<DotCMSNavigationItem[]>;

Why Use navigation.get()?#

  • Build dynamic menus and site trees with minimal configuration
  • Avoid manual parsing or custom REST calls
  • Support localized navigation out of the box
  • Easily control navigation depth for responsive and nested UIs

client.content.getCollection(): Fetching Content Collections#

The client.content.getCollection() method allows you to query and retrieve a collection of content items of a specific type from dotCMS. It uses a builder pattern so you can fluently compose queries with filters, pagination, sorting, and more.

Why Use getCollection()?#

  • Query exactly the content you need
  • Chain filters, sorting, and pagination cleanly
  • Works great for lists, search results, or dynamic components
  • Fully type-safe when used with TypeScript interfaces

Basic Usage#

Here's how to fetch the first 10 items from the "Blog" content type:

const blogs = await client.content.getCollection('Blog').limit(10).page(1);

Filtering and Querying Content#

You can apply query filters using a fluent builder pattern:

const filtered = await client.content
    .getCollection('Blog')
    .query((qb) => qb.field('title').equals('dotCMS*'))
    .limit(5)
    .sortBy([{ field: 'publishDate', direction: 'desc' }]);

The table below outlines the builder pattern's methods:

QueryBuilder MethodTypeResultExplanation
.field('foo')Fieldfoo:{bar}Defines a field name to query, awaiting a value to be supplied via the .equals() method. Multiple such assignments can be made if joined together via operator methods such as or().
.excludeField('foo')Field-foo:{bar}Defines a field name to exclude from the query, awaiting a value to be supplied via the .equals() method, or several combined through operators.
.equals('bar')Assignment{foo:}barSupplies a value to a preceding field method. Multiple .equals() calls may be joined through operator methods.
.raw('foo')RawfooAdds raw input as output to the query; requires use of Lucene syntax directly.
.and()OperatorANDJoins two query clauses — whether assignments or field/assignment pairs — such that results will be returned when both halves apply.
.or()OperatorORJoins two query clauses such that results will be returned when at least one half applies.
.not()OperatorNOTUnary operator; query will return only results where the subsequent clause does not apply.
.build()Constructorn/aOutputs query string.

The following example displays all of the builder class's methods, generating a complex Lucene query:

let queryBuilder = new QueryBuilder();
const myQuery = queryBuilder
            .field('contentType')
            .equals('Blog')
            .or()
            .equals('Activity')
            .excludeField('conhost')
            .equals('my-super-cool-site')
            .field('languageId')
            .equals('2') // spanish
            .and()
            .field('deleted')
            .equals('false')
            .raw('+summary:Snowboard')
            .not()
            .equals('Swiss Alps')
            .build();

The above myQuery variable will have the following value:

+contentType:Blog OR Activity -conhost:my-super-cool-site +languageId:2 AND +deleted:false +summary:Snowboard NOT "Swiss Alps"

For additional examples, see the specification page, or the examples below.

Search and Paginate Product Results by Title and Price#

const searchResults = await client.content
    .getCollection('Product')
    .query((qb) => qb.field('title').equals('Book*'))
    .sortBy([{ field: 'price', order: 'asc' }])
    .limit(10)
    .page(2);

console.log(searchResults);

Localized Query with Conditional Status Filtering#

const events = await client.content
    .getCollection('Event')
    .query((qb) => qb.field('status').equals('Live').or().equals('Scheduled').build())
    .language(2) // e.g., French
    .limit(5);

console.log(events);

Raw Search + Sorting + Pagination#

const images = await client.content
    .getCollection('Image')
    .query('+title:vacation*')
    .sortBy([{ field: 'publishDate', order: 'desc' }])
    .limit(10)
    .page(1);

console.log(images);

Available Builder Methods#

The builder returned by getCollection() supports the following methods:

MethodArgumentsDescription
query()string | BuildQueryFilter content using query builder or raw query
limit()numberSet number of items to return
page()numberSet which page of results to fetch
sortBy()SortBy[]Sort by one or more fields
render()NoneEnable server-side rendering of widgets
draft()NoneRetrieve draft content
variant()stringFilter content by variant ID
depth()numberSet depth of related content
language()number | stringSet content language
then()OnFullfilled<T>, OnRejectedHandle promise fulfillment or rejection. Not needed if using async/await.

Method Signature#

getCollection<T = DotCMSBasicContentlet>(
  contentType: string
): CollectionBuilder<T>;

Using the SDK with TypeScript#


As mentioned earlier, dotCMS provides a rich set of types provided by the @dotcms/types@next package. These types can be leveraged to ensure proper typing for your page and content data, enhancing type safety and developer experience.

Defining Page Response Types#

You can use these types to define interfaces for your content and page structures, ensuring that your application benefits from TypeScript's type-checking capabilities:

// Import the base DotCMS types
import { DotCMSPageAsset, DotCMSBasicContentlet } from '@dotcms/types';

// Define the page structure by extending the base DotCMSPageAsset
interface AboutUsPage extends DotCMSPageAsset {
    vanityUrl: {
        url: string;
    };
}

// Define interfaces for your content types
interface BlogPost extends DotCMSBasicContentlet {
    title: string;
    identifier: string;
    urlTitle: string;
    blogContent: {
        json: string;
    };
}

interface TeamMember {
    name: string;
    position: string;
    bio?: string;
}

// Define the content response structure
interface AboutUsContent {
    blogPosts: BlogPost[];
    teamMembers: TeamMember[];
}

// Use the type parameters to get fully typed responses
const response = await client.page.get<{ pageAsset: AboutUsPage; content: AboutUsContent }>(
    '/about-us',
    {
        languageId: '1',
        fireRules: true,
        graphql: {
            page: `
            title
            pageId
            vanityUrl {
                url
            }
        `,
            content: {
                blogPosts: `
                BlogCollection(limit: 3) {
                    title
                    identifier
                    ...blogFragment
                }
            `,
                teamMembers: `
                TeamMemberCollection(limit: 5) {
                    name
                    position
                    bio
                }
            `
            },
            fragments: [
                `
                fragment blogFragment on Blog {
                    urlTitle
                    blogContent {
                        json
                    }
                }
            `
            ]
        }
    }
);

const { pageAsset, content } = response;

// Now you get full TypeScript support
console.log(pageAsset.vanityUrl.url); // TypeScript knows this exists
console.log(content.blogPosts[0].title); // TypeScript knows this exists
console.log(content.teamMembers[0].position); // TypeScript knows this exists

Defining Content Response Types#

You can define interfaces for your content types to get full type safety:

import { DotCMSBasicContentlet } from '@dotcms/types';

interface BlogPost extends DotCMSBasicContentlet {
    title: string;
    publishDate: string;
    author: string;
    blogContent: {
        json: string;
    };
    urlTitle: string;
    tags: string[];
}

const response = await client.content.getCollection<BlogPost>('Blog');

response.contentlets.forEach((post) => {
    console.log(post.title); // Type-safe access
    console.log(post.author);
    console.log(post.tags.join(', '));
});

How to Enable Page Editing in dotCMS#


By default, the @dotcms/client SDK is read-only. It's designed to fetch content from dotCMS—pages, navigation, and collections—but it doesn't make pages editable in the dotCMS backend.

To make your pages editable using the dotCMS Universal Visual Editor (UVE), you'll need to pair this SDK with one of our supported front-end integrations.

Use an Official SDK:#

If you're using a modern JavaScript framework like React or Angular, we strongly recommend starting with one of our official UVE integrations. These pair the @dotcms/client SDK with framework-specific tooling for the Universal Visual Editor:

You can also see them in action within our full-stack examples:

These integrations come pre-wired with everything you need to:

  • Enable editable pages inside dotCMS using the UVE
  • Render layouts and content containers
  • Fetch page and content data using @dotcms/client

⚠️ Advanced Only: Custom UVE Integration#

If you’re building with a framework we don’t yet support, you can build your own UVE integration using the low-level @dotcms/uve package.

This is not a recommended path.

Custom UVE implementations are complex, require a deep understanding of dotCMS internals, and are not actively supported.

This route is intended only for advanced use cases, such as wiring up layout rendering, editable regions, and UVE behavior manually.

That said, if you’re experienced and want to explore it, you can review the @dotcms/uve source and docs here.

dotCMS Support#


We offer multiple channels to get help with the dotCMS Client SDK:

  • GitHub Issues: For bug reports and feature requests, please open an issue in the GitHub repository.
  • Community Forum: Join our community discussions to ask questions and share solutions.
  • Stack Overflow: Use the tag dotcms-client when posting questions.

When reporting issues, please include:

  • SDK version you're using
  • dotCMS version
  • Minimal reproduction steps
  • Expected vs. actual behavior

Enterprise customers can access premium support through the dotCMS Support Portal.

How To Contribute#


GitHub pull requests are the preferred method to contribute code to dotCMS. We welcome contributions to the DotCMS UVE SDK! If you'd like to contribute, please follow these steps:

  1. Fork the repository dotCMS/core
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure your code follows the existing style and includes appropriate tests.

Licensing Information#


dotCMS comes in multiple editions and as such is dual-licensed. The dotCMS Community Edition is licensed under the GPL 3.0 and is freely available for download, customization, and deployment for use within organizations of all stripes. dotCMS Enterprise Editions (EE) adds several enterprise features and is available via a supported, indemnified commercial license from dotCMS. For the differences between the editions, see the feature page.

This SDK is part of dotCMS's dual-licensed platform (GPL 3.0 for Community, commercial license for Enterprise).

Learn more at dotcms.com.

Found an issue with this documentation? Report it on GitHub