DEV Community

Cover image for What I have learned of building a chatbot in GatsbyJS, Contentful and Ninetailed
Andy Kaiser
Andy Kaiser

Posted on

What I have learned of building a chatbot in GatsbyJS, Contentful and Ninetailed

To begin with, building a Chatbot with GatsbyS and Contentful may appear strange, but it all began with a customer personalization exercise and experiment at my company Ninetailed.

And, spoiler alert, our GatsbyJS, Contentful, and Ninetailed based Chatbot works great and, more importantly, it was fun and quick to develop (we finished it in a couple of hours).

GatsbyJS, Contentful & Ninetailed - An Introduction

We use GatsbyJS for our website ninetailed.io because it is great for creating lightning-fast, accessible, and SEO-friendly websites. It is also easy to use and integrates seamlessly with our headless CMS Contentful.

Ninetailed, on the other hand, is a personalization and optimization platform for modern websites. Not to mention that Ninetailed has a GatbsyJS plugin and a Contentful App to make integration in this stack simple and quick.
Personalizing our website with a Chatbot

We had the idea to integrate a chatbot with the Ninetailed personalization platform during a brainstorming session about personalization experiences. An interactive chatbot is ideal for gathering information from visitors such as intent, job roles, and adapting website content to user data and intent. As a result, the content journey and customer experience are enhanced.

The next step is to select a Chatbot solution. There are numerous advanced Chatbot solutions available, such as Solvemate or Intercom, that combine the power of natural language processing (NLP), rule-based conversations, and human operators.

Following our API-first, rapid prototyping, and agile development philosophy, we decided to create a prototype using our personalization API and SDKs. After all, we want to personalize our website based on visitor intent, and our personalization engine can handle rule-based audiences.

Let's build a chatbot

For our website stack we use GatsbyJs, Contentful, Tailwind CSS and Ninetailed for website personalization. This stack will serve as our starting point...

1. Chatbot flow

First and foremost, we define the chatbot flow. We keep things simple because we're working on a prototype. In this first iteration, we use a decision tree model with two steps and two data points or user traits:

  • The first step is to request the first name in order to personalize the page and create a demo effect. This also personalizes the guide experience, and we want to highlight our merge tag personalization feature.
  • The second step is to inquire about the visitor's role. This allows us to match the visitor to one of our personas and adapt the website's content. The role is an important aspect of our marketing personas, as it relates to the visitor's intent.

Alt Text

Chatbot flow

2. Chatbot UI

Because we use Tailwind UI as design system, creating chatbot UI elements like the bubble and chat window is simple and quick.

Alt Text

Chatbot UI example

3. Contentful content model

We create a new content model in Contentful with the following fields:

  • Name used as entry title.
  • Image for the chatbot
  • Message for the chatbot.
  • Placeholder for the input field.
  • Button text for the button.
  • Event ID to define the event to send with the value of the input.

We have a lot of flexibility with this content structure because we can create the chatbot content within Contentful CMS without changing any code and adapt the content variants for personalization with the Ninetailed Personalization App.

4. Ninetailed personalization

Finally, integrating the code with Ninetaled takes only a few minutes because we only need to wrap the chat component with the <Personalize /> component (and install the GatbsyJS plugin if you haven't already).

Chatbot component code example:

import React from "react";
import { ChatFragment } from "../../../@generated/types";

import { ChatApiProvider } from "./ChatApiProvider";
import { Container } from "./Container";
import { Body } from "./Body";
import { Launcher } from "./Launcher";

export const Chat: React.FC<ChatFragment> = (props) => {
 return (
   <ChatApiProvider>
     <Container>
       <Body {...props} />
       <Launcher />
     </Container>
   </ChatApiProvider>
 );
};
Enter fullscreen mode Exit fullscreen mode

Ninetailed personalization code example:

import React, { useEffect } from "react";
import { GatsbyImage, getImage } from "gatsby-plugin-image";
import { Form, Field } from "react-final-form";
import {
 Profile,
 useAnalytics,
 useProfile,
} from "@ninetailed/client-sdk-react";
import { createRenderNinetailedMergetag } from "@ninetailed/client-sdk-gatsby-contentful";
import { BLOCKS, INLINES, MARKS } from "@contentful/rich-text-types";
import { Options } from "@contentful/rich-text-react-renderer";
import { Link as GatsbyLink } from "gatsby";

import { ChatFragment } from "../../../@generated/types";

import { renderRichText } from "../RichText";
import { sanitizeSlug, Link } from "../Link";
import { useChatApi } from "./ChatApiProvider";
import { CloseButton } from "./CloseButton";

const options = (profile: Profile): Options => ({
 renderNode: {
   [BLOCKS.PARAGRAPH]: (node, children) => (
     <p className="text-sm text-gray-500">{children}</p>
   ),
   [INLINES.HYPERLINK]: (node, children) => (
     <a
       href={node.data.uri}
       target="_blank"
       className="text-indigo-600 hover:text-indigo-500"
     >
       {children}
     </a>
   ),
   [INLINES.ENTRY_HYPERLINK]: (node, children) => (
     <GatsbyLink
       to={sanitizeSlug(node.data.target?.slug)}
       className="font-medium text-indigo-600 hover:text-indigo-500"
     >
       {children}
     </GatsbyLink>
   ),
   [INLINES.EMBEDDED_ENTRY]: (node, children) => {
     if (node.data.target.__typename === "ContentfulLink") {
       return (
         <Link
           className="inline-flex my-2 mr-2 items-center px-2.5 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
           {...node.data.target}
         />
       );
     }

     return (
       <span className="mr-1">
         {createRenderNinetailedMergetag(profile)[INLINES.EMBEDDED_ENTRY](
           node,
           children
         )}
       </span>
     );
Enter fullscreen mode Exit fullscreen mode

5. Variants and audiences

In Contentful, we must now create variants and specific audiences for the chatbot content. It only takes a few clicks to create personalization variants with Ninetailed and Contentful. If the visitor has filled out a first name and has chosen a role in the chatbot, we create a variant for the chat message.

We use user traits and events for the audiences:

  • Visitors who have filled out their first names.
  • Visitors who have chosen a role.

Alt Text

Audience first name

Alt Text

Audience developers

Learnings and next steps

This chatbot integration took us only a few hours to complete. It was not only quick to make, but also enjoyable to work on. This prototype project demonstrated:

  • Working with your own stack and product must be exciting.
  • Think outside the box and be inventive in the application of your own product.
  • Developer experience with your stack and tools is critical. GatbsyJS, Contentful and Ninetailed have an excellent developer experience.
  • A design system enables rapid prototyping.

As the prototype was successful in development, and after a week, the chatbot's engagement rates are great, we intend to:

  • Add more steps to the chatbot flow.
  • Integrate more powerful chatbots.
  • Create SDKs or integrations with chatbots.

Finally, please let me know what you think about this chatbot prototype and how we used GatsbyJS, Contentful, and Ninetailed to create it. If you want to create a similar chatbot or customize your Contentful website with personalized content, you can install the Ninetailed app for free from the official marketplace.

Top comments (0)