October 11, 2019 - Projects

Adding comments to a Gatsby blog using Contentful Pt.1

Interested in learning how to build comments into your Gatsby site using Contentful that doesn't require third party scripts or ads?

Wall with text displaying the words I love you in various ways.


Comments are an integral part of any blog. Due to the nature of static sites, however, it can be quite cumbersome to have commenting functionality on your site. You can store them in Git but you have to rebuild the site in order to update the comments for all users. There is the option of Disqus but this either costs money, or you have to run ads and this isn't really appealing to a lot of people.

I use Contentful as my CMS of choice when building sites, yes it is expensive but the free tier is very generous and their UI and documentation is second to none.

When I decided to update my personal site, I wanted to focus on technical content like this as opposed to the less technical (easier to digest for the regular internet user ) that I post over on my other web agency site dazzle works. That and give people the option to provide feedback. The natural way to do that is to have the ability for your site visitors to leave comments. So over a weekend I sat down and built a commenting system from scratch using Gatsby and Contentful. It was straight forward enough and over the next two posts I am going to guide you through the setup and implementation of comments ( and replies ) for your Gatsby ( or otherwise ) site hosted on Netlify.

Heres an example of how it works:

Commeting functionality


This tutorial assumes you know how to set up a blog using Gatsby and Contentful while also being familiar with Netlify functions. If not I can't recommend this tutorial enough. If you don't know much about Netlify functions you can read about them here. This tutorial will focus purely on the commenting functionality and not how to work with Contentful and Netlify functions so we won't be diving into the css or jsx.

Setting up

First things first, we need to set up our content model. You can set this up however you like but the important parts are Enable Comments and Comments. Enable Comments is a boolean which basically tells Gatsby whether or not to display the commenting functionality on a given post. Comments is a JSON object. Enable Comments is the only required field of the two.

Contentful Content Model

Our JSON object will use the following structure shown in this example:

         "message":"Hi, this was a great post",
               "message":"Thanks David, appreciate that!",

We have a JSON object which has a key of comments and value which is an array of comments. Each comment will have an ID in order to reference for adding replies. A name handle and message... I feel asking for an optional handle that will be linked in their name is better than an email. Replies which is an array of replies to the comment, empty by default. A timestamp used to show when the comment was made and to help prevent malicious users attempting to spam comments. Pretty straight forward, nothing too complicated yet.

Like I said earlier, using git would force you to rebuild the site to get the comments to show. I wanted something a little quicker so I decided to use Netlify Serverless functions. Netlify's free tier gives you 125,000 request per month for free and scales automatically if needed. We will be using two functions for this project. One for initially getting the comments and another for adding a comment. So if we do a little math that means we can make 2k requests a day for retrieving and adding comments per month for free.

Getting our comments

"use strict"
const contentful = require("contentful-management")
exports.handler = function(event, context, callback) {
    async function main() {
        // Post ID from get request
        const ID = await event.queryStringParameters.ID
        // Start with empty array
        let postComments = []
        // Connect to contentful
        const client = contentful.createClient({
            accessToken: "XXXX-XXXX-XXXX"
        // Get the entry based on post ID.
        await client
			.then(space => space.getEnvironment("master"))
			.then(environment => environment.getEntry(ID))
			.then(entry => {
            // If no comments exist
            if (entry.fields.comments === undefined) {
                // Create the JSON needed to store comments
                entry.fields.comments = {
                    "en-US": {
                        comments: []
                // Update entry
                return entry.update()
            } else {
                // Grab the comments
                entry.fields.comments["en-US"].comments.forEach(comment => {
        }).then(() => {
            // Callback with comments to update state
            callback(null, {
                statusCode: 200,
                body: JSON.stringify({
                    comments: postComments

Also, In order to use async-await we need to declare a function using it inside the Netlify function.

So let's run through this...

  1. We are grabbing the Post ID from the client side react component ( more on this later ) to use in the function to retrieve the correct comments.

  2. Create an empty array to store comments retrieved from Contentful.

  3. Connect to contentful and get the post based on the ID.

  4. If there are no comments stored, create the JSON object needed to store comments and update the post.

  5. If there is comments, loop over them and add them to the array we declared earlier.

  6. Callback with the comments to store them in component state.

I didn't want to have to manually define the JSON object for each post I made. Since there was no way to have a default value in the content model I had to do a check in the Netlify function.

Once this is setup we need to make a GET request to the serverless function to get the comments. In your client-side react component you can do this in the componentDidMount() lifecycle hook. I suggest doing this in the same component you use as a template for you blog posts. You can use whichever avenue you want for making the GET request. I use axios in the below example.

componentDidMount() {
     const ID = this.props.data.contentfulBlogPost.contentful_id
     axios.get("/.netlify/functions/<your-function-name>", {
         params: {
             ID: ID
     }).then(response => {
             comments: response.data.comments
     }).catch(error => {

Again, pretty straightforward, nothing too complicated. This is all you need in order to get started. If you use dummy data as I have in your Contentful post it should store them in state for you to display as you please. This is all good but wouldn't it be better if we had real data coming from real comments made by real people..?

In the next post, we will dive into that!

Leave a comment
Built with Gatsby JS, Contentful & Netlify © 2021