Building Scalable Headless Solutions
Szymon, Frontend Developer

By Szymon

November 26, 2023

Optimizely Graph and Next.js: Building Scalable Headless Solutions

Optimizely Graph harnesses the capabilities of GraphQL, an intuitive and efficient query language to, transform content within an Optimizely CMS into a structured, interconnected graph. Complementing this, Next.js, a React-based frontend framework, empowers developers to build performant and SEO-friendly web applications, enabling static and dynamic rendering and many more amazing features that can enhance your headless solution.

In this article we delve into the symbiotic relationship between Optimizely Graph and Next.js, exploring how this pairing facilitates the crafting of dynamic headless experiences, from enabling draft modes and On-Page Editing to harnessing static site generation. We'll also investigate the utilization of webhooks for efficient page revalidation, enabling seamless updates across web applications.

What is Optimizely Graph used for?

Using Optimizely Graph we are able to separate our admin panel from our application, the so called headless, since we have two separate applications that are independent of each other. Headless in Optimizely has long been possible by using the Content Delivery API, but Graph simplifies a lot of things.

What is the Optimizely Graph used for?

How does Optimizely Graph work?

Optimizely Graph is a separate service that is hosted on a CDN, made fast by implementing the latest, most modern technologies using global serverless Edge computing, auto scaling microservices and the latest search engine.

There are two ways to deliver content to the Graph service:

  1. Scheduled job
  2. Event Triggering, for example publishing a page.

The Content Delivery API is used under the hood, delivering content to Graph. When you want to introduce something custom, such as adding business logic to a block, you can do so using an override of the serialization used in the Content Delivery API.

In the image below we can see how the Optimizely Graph works. It all starts in the admin panel, in the picture labeled with the Optimizely logo. From there, using the Content Delivery API, the content goes to the GraphQl Server. GraphQl Server is hosted on Azure and is embedded on a CDN. The GraphQl Server combines the admin panel and frontend application used by users. The frontend application communicates directly with GraphQl Server, receiving all the necessary data. How does Optimizely Graph work? Source: world.optimizely.com

Support for Commerce

As of early December, Optimizely Graph has been officially released and is production ready. The released version supports CMS only and allows read-only options. At a recent webinar held by Optimizely, the company said that they are getting a lot of requests for Commerce support and it is in the approval stage by Project Management. Keeping in mind that commerce is much more complicated than CMS, it may take longer to work on this. However, using other Optimizely products like Content Delivery API, we are able to implement Headless Commerce. There is also an option to use Graph for CMS-related stuff, and Content Delivery API for commerce-related stuff.

Personalization

Personalization as we know it so far, i.e. creating visitor groups and adding personalization in Content Area and XHTML strings, will not work.

Here's where other products can help, like Optimizely Web Experimentation, where you can create personalized campaigns and immediately measure which variance converts better. However, this is an additional product charged separately.

There is another option that is being worked on: the integration of Optimizely Graph with Optimizely Data Platform RLS (Real Time Segment), which is the next generation of “Visitor Groups”. ODP is also an additional product that is charged separately.

Content Recs

Content Recommendation works by scraping the page source of the site. if it is valid HTML, there should be no problem with it. If we use Server Side Rendering, there is pure HTML code in the page source, so with SSR, Content Recommendations works. The problem with Content Recs is that if you choose client-side rendering, it means that non-native HTML elements such as <teaser-block/> are included in HTML, so the scraper is not able to collect the correct data.

Hosting on DXP

It is possible to continue to have the frontend application hosted on DXP, then the client app (Node.js) and the backend (.net) are served on the same address by proxying requests from .net to the Node.js process. An example of such a solution can be found here Hosting on DXP Source: Github

Vercel is the recommended hosting platform for Next.js to fully leverage its capabilities, such as Incremental Static Regeneration (ISR) (example of code), image and font optimization. By hosting Next.js on Vercel, you can achieve better performance due to its seamless integration with Next.js and support for these advanced features.

Vercel's administration panel provides a user-friendly interface for managing deployments, making it accessible even to non-technical users. This allows for easy deployment to production after reviewing changes on staging. While there are inherent risks in allowing non-technical users to deploy changes, for small changes like increasing font size, the risks are minimal. The clear and intuitive interface of Vercel's administration panel makes it convenient for non-technical users to manage deployments with confidence.

An example of a starter for Optimizely Feature Flags with Next.js is available for preview and use here.

Understanding Next.js Rendering Strategies

Next.js employs three main server rendering strategies:

  1. Static Rendering (Default): Routes are pre-rendered at build time or after data revalidation. The rendered result is cached and can be distributed via Content Delivery Networks (CDN). This strategy is suitable for static content like blog posts or product pages.

  2. Dynamic Rendering: Routes are rendered for each user at request time. This method is ideal for personalized data or information specific to each user, such as cookies or search parameters.

  3. Dynamic Routes with Cached Data: Next.js allows for routes with a mix of cached and uncached data. This flexibility means you can have personalized, dynamic content while benefiting from caching. For instance, an e-commerce page might use cached product data along with uncached, personalized customer information.

These server rendering strategies offer benefits like enhanced performance, improved security and better initial page load times. Leveraging Next.js's capabilities, developers can efficiently manage and render content, allowing for highly personalized and dynamic web experiences in your headless solution.

Fetching data from Optimizely Graph

A very useful thing when working with Optimizely Graph is codegen for GraphQL Schema -
@graphql-codegen/cli
. With this tool, all we need to do is create the appropriate snippets or queries for our Optimizely Graph, and the CLI will generate a fully-typed SDK for us.

Let’s configure our codegen. First, install following dependencies:

Now, we need to create a config file where we define plugins, schema source, destination file etc.

This configuration will make sure that our SDK and types will be generated in the
./src/types/generated.ts
based on the Optimizely Graph schema and fragments and queries defined in the
./src/graphql/*
. Now, let’s create our custom fetcher that we will use to query data from the Optimizely Graph.

The variable:

is a generated base64 string based on your AppKey and AppSecret credentials. For more details I recommend you to take a look at Kunal’s article

Let’s create a wrapper function around our
optimizelyFetch
that maps the values properly to the
getSdk
function which is an auto-generated SDK.
In the
./src/graphql
(path defined in the
documents
field in the codegen configuration file) create your first query:

After properly configuring codegen and firing the command that generates the SDK, we get a fully-typed client.

fully-typed client

Draft Mode with Optimizely Graph and Next.js

With Optimzely and Next.js we can easily configure previews, drafts and on-page editing to fully take advantage of the headless architecture. In order to let Optimizely know what is the URL to our Frontend, we need to follow a few simple steps.

Firstly, go to the
Manage Websites
section in the CMS settings. Go ahead and create a website. The important thing at this point will be to set the appropriate host names. You need to add one line for the backend application and one for the frontend application, remembering to set the Primary type for the frontend application:
Manage Websites CMS settings
Now, let’s handle displaying correct route in the Preview Mode. By default, the generated URL adds
/episerver/cms/content/**/*
pathname to the configured host and passes it to the iframe. We can redirect all requests from that URL to our custom API handler that will turn on the draft mode for the corresponding page.

Example:

is redirected to

Create an API route that will handle the draft mode:

The
[[…content]]
segment is a naming convention that let’s you catch all route segments, which will be available in the params object argument.

Let’s handle the draft mode in the Page component:

Be careful here though - using cookies in a page component turns it to be dynamically rendered - unless it’s used in
if
block that checks for the draft mode.

The optimizely script to utilize On-Page Editing feature:

Draft Mode

data-epi-edit

To enable on page editing (OPE) we need to add an attribute to the html that will enable this, you can read more about it in the documentation

ope.png

Static Site Generation

Static Site Generation (SSG) is a powerful feature in Next.js that enables the pre-rendering of pages at build time. During the build process, Next.js generates HTML files for each page in your application. These HTML files are static, meaning they represent the state of the page at the time of the build. The pre-rendered HTML files can be served to users without requiring server-side rendering for every request.

Benefits of Static Site Generation in Next.js:

  1. Improved Performance: Since the pages are pre-rendered at build time, users receive static HTML files, reducing the need for server-side processing during runtime. This leads to faster page loads and improved overall performance.

  2. SEO Optimization: Search engines favor static HTML content. SSG helps improve search engine optimization (SEO) by providing crawlers with easily indexable and readable content. This can positively impact a website's search engine ranking.

  3. Lower Server Load: Static pages can be served directly from a content delivery network (CDN) without the need for server-side processing. This reduces the load on the server, allowing it to handle more concurrent users efficiently.

  4. Cost Efficiency: Serving static content is typically more cost-effective than dynamically generating content for each user request. With SSG, you can generate pages during the build process, reducing the need for server resources during runtime.

  5. Better User Experience: Static pages load quickly, providing a smoother and more responsive user experience. Users see the content faster, leading to higher user satisfaction and engagement.

  6. CDN Compatibility: Static files can be easily distributed across a content delivery network, ensuring that the content is delivered from servers geographically closer to the user. This minimizes latency and further enhances page load times.

  7. Offline Support: Static pages can be easily cached, enabling offline access for users. Once the pages are loaded, they can be stored in the browser cache, allowing users to access the content even without an internet connection.

How to Achieve This with Optimizely Graph:

In Next.js, there is a method called generateStaticParams that must return all static routes. To obtain this information, we need to query Optimizely Graph for all routes:

The GraphQL query to the Content Graph:

Implementation in TypeScript:

Considering that our project uses
[[…page]]
(check Next.js Dynamic Routes), we need to split the path into a string array, such as /en/alloy-meet ⇒ [’en’, ‘alloy-meet’]. Therefore, we perform a split operation

In summary, Static Site Generation in Next.js offers a way to generate performant, SEO-friendly, and cost-effective websites by pre-rendering pages at build time. It leverages the benefits of static content while providing the flexibility and convenience of a dynamic web framework.

Using Webhooks for Page Revalidation (ISR)

Let's start by understanding what ISR (Incremental Static Regeneration) is.

Next.js empowers you to create or update static pages after building your site. Incremental Static Regeneration (ISR) allows you to utilize static generation on a per-page basis, eliminating the need to rebuild the entire site. With ISR, you can maintain the advantages of static pages while effortlessly scaling to millions.

In essence, ISR enables you to instruct Next.js to update the cache for a specific page and use the most recent published content.

Now the question arises: How do we know when the content in the content graph has been updated and returns the freshest content? This is where webhooks come into play. You can configure a webhook to inquire about content revalidation from the provided API when it's ready. The link to configure the webhook can be found here:

Optimizely Webhook Configuration

On this page, you need to choose the type of authentication. I opted for Header HMAC authentication (epi-hmac xxx), and the token used here is also employed for fetching unpublished content in draft mode. The token is a combination of AppKey and AppSecret. You can learn more about it here.

Before configuring the webhook, we need to create an API route that will handle the revalidation logic. For us, this route is

api/revalidate
.

Tip:

To locally test the webhook communication, you can use ngrok tunneling. It will proxy your http://localhost:3000 to https and generate a randomly assigned link. After creating it, you can use that link for webhook configuration.

Webhook Configuration: Webhook Configuration

Example:

Example
requestJson
Unfortunately, the webhook only returns the
GUID
and not the
RelativePath
. To extract the path, we need to query the Optimizely graph for information about the page based on the GUID.

All these components allow us to generate the entire site during production builds and return all pages from the cache. When we publish a new change to one of the pages, we only revalidate that specific page, enabling a seamless and efficient process.

Pros and Cons of Optimizely Graph and Next.js Headless Solution

ProsCons
Performance (SSR, SSG, ISR)Additional layer of complexity
Uses EdgeNo support for Commerce
Uses latest technologyA more expensive solution than the traditional Hybrid in terms of development
Attractive for devsPublishing content in CMS does not equate to an immediate change on the site
Good SEO
A single source for content CMS -> web, mobile app…

Optimizely Graph has several advantages, including improved performance through server-side rendering (SSR) and static site generation (SSG). It leverages edge computing technology and utilizes the latest technology stack, making it attractive for developers. It also offers good search engine optimization (SEO) capabilities and provides a centralized content management system (CMS) for managing content across web and mobile applications.

However, there are some drawbacks to consider. Implementing the solution adds an additional layer of complexity to the development process. It currently lacks support for commerce functionality. The development costs can be higher compared to traditional hybrid solutions. It's also important to note that publishing content in the CMS does not guarantee immediate changes on the website.

In summary, while the solution offers performance benefits, modern technology and a centralized content management system, it also presents complexities, limitations in commerce support and higher development costs. It's crucial to assess these factors based on specific requirements before deciding on its adoption.

Best Practices and Tips

Avoid using Apollo Client

Avoid using Apollo Client in your Next.js project. While it is a powerful GraphQL client, Next.js provides robust native support for fetching data using the built-in

fetch
function. Apollo Client, being feature-rich, can introduce unnecessary overhead to your project.

Next.js comes with several built-in features that make it well-suited for handling GraphQL requests. It provides extensive capabilities, such as cache tags and revalidation, making it unnecessary to rely on external heavyweight libraries like Apollo Client.

By sticking to Next.js native features and optimizing your GraphQL requests using the built-in fetch function, you can keep your project lightweight, efficient, and well-aligned with the framework's best practices.

Use Tailwind CSS

We recommend using Tailwind CSS as it provides an optimal solution tailored for Next.js. Tailwind CSS generates all styles during the build process into a single file, which is typically very small (in our Next.js projects, the CSS file is around 16-30kb). This approach enhances performance and aligns well with Next.js conventions.

UI Library

If you're in search of a UI library with versatile components, we highly recommend choosing Shadcn UI. It has proven to be an excellent choice in several of our projects. Shadcn UI offers extensive customization options and has consistently met all our requirements.

More about shadcn

Use Codegen

Utilizing code generation alongside Optimizely Graph can save a significant amount of time. This is because you won't need to manually type page or block types. Code generation also creates TypeScript methods for interacting with Optimizely Graph. All you have to do is create a GraphQL query and run the code generation command. Notably, you can pass your custom fetcher, enabling customization according to your requirements.

Conclusion

In conclusion, the integration of Optimizely Graph and Next.js offers a powerful solution for building scalable headless applications. By leveraging GraphQL capabilities through Optimizely Graph, developers can structure and interconnect content within Optimizely CMS in a more efficient and intuitive manner. This is complemented by Next.js, a React-based frontend framework that enables the creation of performant and SEO-friendly web applications, supporting both static and dynamic rendering.

The symbiotic relationship between Optimizely Graph and Next.js allows for the crafting of dynamic headless experiences. This includes features like draft modes, On-Page Editing, static site generation, and efficient page revalidation through webhooks.

In summary, the Optimizely Graph and Next.js integration provides a robust foundation for developing scalable, performant, and SEO-friendly headless applications, with the flexibility to adapt to various use cases and requirements.

Hatimeria understands the importance of staying up to date with the latest trends in online business. That's why we have focused on mastering headless commerce to provide you with top-notch solutions. Our developers know everything about headless systems, decoupled frontend frameworks and powerful APIs, which allows us to create customized ecommerce experiences that meet your specific needs.

By using headless architecture, we can help you create seamless shopping experiences across different channels, improve website performance, handle increased traffic and give you more flexibility in managing your online store.

Don't miss out on the future of ecommerce. Partner with Hatimeria and embrace the limitless possibilities of headless commerce.

Would you like to innovate your ecommerce project with Hatimeria?

Author
Szymon, Frontend Developer
Szymon
Developer

Football and Optimizely enthusiast. Able to conjure up goals not only on the pitch but also in a FIFA game. He is an Optimizely-certified developer and Fifa-certified player. When he's not delivering top-notch programming, he can be found in the gym honing his skills and training for the next game.

Read more Szymon's articles

Our Latest Thinking

Interested in something else?

Office

Meet the team

Learn more about company and the team.

Join Us

Join us

Make an impact on your career.