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.

Integrate a Next.js project with Optimizely Content Management System Software as a Service (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 set up ensures type safety, optimized queries, and a streamlined developer experience for managing content in CMS.

Prerequisites

Before you begin, ensure that you have:

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

1. Create a Next.js project

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

2. Install GraphQL dependencies

npm install @apollo/client graphql

3. Set up Apollo Client with cached templates

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

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;

4. Configure environment variables

Create a .env.local file and add:

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

5. Create your first component

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

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>
  );
}

6. Create a landing page component

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

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>
  );
}

7. 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 to see your content and landing pages loaded from Optimizely Graph.