Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

Dev guideRecipesAPI ReferenceChangelog
Dev guideRecipesUser GuidesNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Quick start guide: Next.js/React

Learn how to connect your GraphQL endpoint, query content, and display Content Management System Software as a Service (CMS SaaS) data using Apollo Client.

Use this guide to integrate a Next.js project with Optimizely Content Management System (CMS) SaaS using Apollo Client. Configure a GraphQL client with cached templates, create reusable components to fetch content and landing pages, and render them efficiently in your application. This configuration ensures type safety, optimized queries, and a streamlined developer experience for managing content in CMS (SaaS).

Prerequisites

Before you begin, ensure you have the following:

  • Node.js (v18 or higher).
  • An Optimizely CMS SaaS instance.
  • API key and Optimizely Graph endpoint.

Create a Next.js project

npx create-next-app@latest my-saas-cms-site
cd my-saas-cms-site

Install GraphQL dependencies

npm install @apollo/client graphql

Configure Apollo Client with cached templates

Create a file named lib/apollo-client.ts and add the following:

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';

const httpLink = new HttpLink({
  uri: 'https://beta.cg.optimizely.com/content/v2?auth=INSERT_YOUR_KEY_HERE&stored=true',
  headers: {
    // Enable cached templates for better performance
    'cg-stored-query': 'template',
  }
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache(),
  defaultOptions: {
    watchQuery: {
      errorPolicy: 'all',
    },
    query: {
      errorPolicy: 'all',
    },
  },
});

export default client;

Configure environment variables

Create a .env.local file and add the following:

NEXT_PUBLIC_OPTIMIZELY_GRAPH_ENDPOINT=https://beta.cg.optimizely.com/content/v2?auth=INSERT_YOUR_KEY_HERE&stored=true

Create your first component

Create a file named components/ContentList.tsx and add the following:

import { gql } from '@apollo/client';
import { useQuery } from '@apollo/client/react';

const GET_CONTENT = gql`
query GetContent($locale: [Locales], $skip: Int = 0, $limit: Int = 10) {
  _Content(
    locale: $locale
    orderBy: { _metadata: { lastModified: DESC } }
    skip: $skip
    limit: $limit
  ) {
    items {
      _metadata {
        displayName
        url {
          default
        }
        types
        published
      }
    }
    total
  }
}
`;

export function ContentList() {
  const { loading, error, data } = useQuery(GET_CONTENT, {
    variables: { locale: ['en', 'NEUTRAL'] },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h1>Latest content from SaaS CMS</h1>
      <p>Total content items: {data._Content.total}</p>

      {data._Content.items.map((item, index) => (
        <div
          key={index}
          style={{
            marginBottom: '1rem',
            padding: '1rem',
            border: '1px solid #ccc',
          }}
        >
          <h3>{item._metadata.displayName}</h3>
          <p>
            <strong>Type:</strong> {item._metadata.types?.join(', ')}
          </p>
          <p>
            <strong>URL:</strong> {item._metadata.url?.default}
          </p>
          <p>
            <strong>Published:</strong>{' '}
            {new Date(item._metadata.published).toLocaleDateString()}
          </p>
          {item._metadata.url?.default && (
            <a
              href={item._metadata.url.default}
              target="_blank"
              rel="noopener noreferrer"
            >
              View content →
            </a>
          )}
        </div>
      ))}
    </div>
  );
}

Create a landing page component

Create a file named components/LandingPageList.tsx and add the following:

import { gql } from '@apollo/client';
import { useQuery } from '@apollo/client/react';

const GET_LANDING_PAGES = gql`
  query GetLandingPages($locale: Locales) {
    LandingPage(locale: [$locale]) {
      items {
        _metadata {
          displayName
          url {
            default
          }
          published
        }
      }
      total
    }
  }
`;

export function LandingPageList() {
  const { loading, error, data } = useQuery(GET_LANDING_PAGES, {
    variables: { locale: 'en' },
  });

  if (loading) return <p>Loading landing pages...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h2>Landing pages</h2>
      <p>Total landing pages: {data.LandingPage.total}</p>
      {data.LandingPage.items.map((page, index) => (
        <div
          key={index}
          style={{
            marginBottom: '1rem',
            padding: '1rem',
            border: '1px solid #ccc',
          }}
        >
          <h3>{page._metadata.displayName}</h3>
          <p>
            <strong>URL:</strong> {page._metadata.url?.default}
          </p>
          <p>
            <strong>Published:</strong>{' '}
            {new Date(page._metadata.published).toLocaleDateString()}
          </p>
          {page._metadata.url?.default && (
            <a
              href={page._metadata.url.default}
              target="_blank"
              rel="noopener noreferrer"
            >
              View page →
            </a>
          )}
        </div>
      ))}
    </div>
  );
}

Use the components in your page

In app/page.tsx, import and render the components.

'use client';
import { ApolloProvider } from '@apollo/client/react';
import client from '../lib/apollo-client';

import { ContentList } from '../components/ContentList';
import { LandingPageList } from '../components/LandingPageList';

export default function Home() {
  return (
    <ApolloProvider client={client}>
      <div style={{ padding: '2rem' }}>
      <h1>Mosey Bank CMS content</h1>
      <ContentList />
      <hr style={{ margin: '2rem 0' }} />
      <LandingPageList />
      </div>
    </ApolloProvider>
  );
}

Result

Run the project locally.

npm run dev

Open your Localhost (http://localhost:3000/) to see your content and landing pages loaded from Optimizely Graph.