Build a Fullstack Chatbot in 20 minutes with React and Node.js: A Step-By-Step Guide

Sammy-Jo Wymer
REWRITE TECH by diconium
10 min readFeb 21, 2024

It’s 2024 and AI and chatbots are no longer just buzzwords — they’re necessities in software development. With this walkthrough, you’ll learn how to create your own custom ChatGPT-like app from scratch using React and Node.js. You won’t need any prior experience with AI in development but basic knowledge of React and Node.js will be helpful.

Setting up the project

If you’re already familiar with setting up a React app, feel free to skip ahead.

To begin, we need to set up our React project. One of the simplest and fastest ways to do this is with Vite.

In the past I always used Create React App but I recently turned to Vite for a much faster and efficient way of setting up my React app. The documentation is also really easy to follow.

1. Open your terminal then navigate to the folder where you want to create your React app (e.g. cd documents will take you to the documents folder).

For more information on simple terminal commands you can read my article Getting friendly with the terminal.

2. Once you’re in the relevant folder in the terminal, run the following command and then follow the instructions in the terminal:
npm create vite@latest

Vite instructions in terminal

The above screenshot shows my terminal and the folder I’m in (dev/2024). Vite will ask you to name your project (as you can see, I named it ai-in-react) and then select a framework. Select React and then TypeScript and then run the commands that Vite provides to complete the setup.

Great! And just like that we have a functioning React app. But before we can proceed, we need to clean up/delete some of the boilerplate code that comes with the Vite setup.

3. Open your newly created app in your IDE of choice. I am using Visual Studio Code:

ai-in-react app in Visual Studio Code

Delete the public and assets folders (highlighted in the screenshot below) and also the index.css file (don’t forget to remove the import for this file in main.tsx).

Then open the App.css file and delete all the contents (we’ll add our own later).

Remove Vite boilerplate

Navigate to the index.html file and remove the link for the Vite icon (highlighted in the screenshot below).

Remove Vite boilerplate

Finally, open the App.tsx file and remove the first three imports (leaving only the import for App.css). Remove the rest of the functionality leaving only an empty App function (highlighted in red in the screenshot below).

Remove Vite boilerplate

Your App.tsx should now contain the following code (and if you’re running the app on your local server, you should see a blank white page).

Notice I also changed the <></> to a div and have added a className:

// App.tsx

import "./App.css";

function App() {
return <div className="container"></div>;
}
export default App;

That’s the initial setup done! We can now start getting our hands dirty with AI…

Setting up OpenAI

In this tutorial, we’ll be using the OpenAI API and so you first need to make sure you have an account (if you’ve used ChatGPT then you will already have an account, if not you can easily set one up here).

Login to your account and then proceed to the API page. In the left sidebar click API keys and you should see a page similar to this:

OpenAI API page

As you can see, I’ve already created an API key. If you don’t have one already you should create one by clicking Create new secret key.

Copy this key and then navigate back to your code. In the root, create a file called .env and add your key as a variable here. For example:

.env file with API key

When using Vite, variables within the .env file should be prefixed with VITE_. For example, VITE_OPEN_AI_KEY

Install the OpenAI Node.js library. To do this, run the following command in your terminal:
npm install openai

Great! Now we’re all ready to use this API :)

Setting up a local server

We need to create a local server to manage our API requests and ensure any data we provide to the API is handled securely.

Creating a server might sound like a daunting task if you’ve never done it before, but we’re going to do it in 6 easy steps.

  1. First, in the root, create a file called server.js.
  2. Then in your terminal, install express with the following command:
    npm install express — this is the package we’ll use to create our web server.
  3. Install cors with the following command: npm install cors — this package will allow our frontend and server to interact without issue.
  4. Add express and cors as imports in the server.js file and create your local server with the following code:
// server.js

import express from "express";
import cors from "cors";

// Initialise express
const app = express();
// Here, we provide a port. You can choose any available port.
const port = process.env.PORT || 3005;

// We add this so that our server and frontend app can interact without issue
app.use(cors());
// We add this line to parse JSON in the request body
app.use(express.json());
// This allows us to see if our server is running ok
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

5. Now, we import and initialise the OpenAI API:

// server.js

import express from "express";
import cors from "cors";
import { OpenAI } from "openai";

const app = express();
const port = process.env.PORT || 3005;
// Assign API key to variable
const apiKey = process.env.VITE_OPEN_AI_KEY;
// Initialise OpenAI API
const openai = new OpenAI({ apiKey: apiKey });

app.use(cors());
app.use(express.json());
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

6. Finally, we add a POST request that will take user input (questions) from the frontend application and send these questions to the OpenAI API via our server, which will then return a response:

// server.js

import express from "express";
import cors from "cors";
import { OpenAI } from "openai";

const app = express();
const port = process.env.PORT || 3005;
const apiKey = process.env.VITE_OPEN_AI_KEY;
const openai = new OpenAI({ apiKey: apiKey });

app.use(cors());
app.use(express.json());
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

// Here, we define the '/chatbot' route to handle questions from our
// frontend React application
app.post("/chatbot", async (req, res) => {
// The 'question' variable is the user's input from the frontend
const { question } = req.body;
// Here is where we communicate with the OpenAI API to create our chatbot.
// We store the chatbot's response in the 'response' variable
const response = await openai.chat.completions.create({
messages: [
// We give the chatbot a role with some content to determine how it will behave
{
role: "system",
content:
"You are a helpful assistant.",
},
// We ask the chatbot to generate an answer based on the user's question
// Remember, this question will come from the frontend
{
role: "user",
content: question,
},
],
// We choose the model we want to use for our chatbot
model: "gpt-3.5-turbo",
// We add a value for max_tokens to ensure the response won't exceed 300 tokens
// This is to make sure the responses aren't too long
max_tokens: 300,
});
// Then we take the text response and display it on the server
// Note: This will only work once we set up our frontend logic
res.send(response.choices[0].message.content);
});

The code for the response variable above is almost a direct copy and paste from OpenAI’s quick start guide:

OpenAI API documentation

The function in the guide above sends a request to the OpenAI API with the prompt “You are a helpful assistant”. It then console logs the response from OpenAI.

You can check that your server is working by running: node server.js in the terminal. You should then see a message in the terminal which says: Server running on port 3005

Now that our server is up and running we can finally move on to creating our chatbot in React.

Creating your React Chatbot

So far, we’ve:
- Created a React app from scratch using Vite
- Gained access to the OpenAI API and integrated it into our code
- Set up our own local server to manage our chatbot

Before we get our hands dirty with the frontend code, we’ll need to install axios with the following command: npm install axios — we’ll use this package to handle our HTTP requests.

Let’s now go back to our App.tsx file and add the necessary functionality to get our chatbot up and running.

// App.tsx

// import useState so that we can update the response we get from the API
import { useState } from "react";
// import axios so we can easily send the user's input to our server
import axios from "axios";
import "./App.css";

function App() {
// We store and update the responses we get from the API with this state
// I've added a default value to the 'response' state that we should see
// when the page initially loads
const [response, setResponse] = useState<string>("Hi there! How can I assist you?");
// We also store the input we get from the user in the 'value' state and
// update it everytime the user types into the input field we have added below
const [value, setValue] = useState<string>("");

// We use this function in the newly added 'input' in the return statement.
// Each time the user types into the input, this function ensures that the
// 'value' state is updated
// We also add a type to the event that we pass in
const onChange = (e: React.ChangeEvent<HTMLInputElement>) =>
setValue(e.target.value);

// This function runs when the user presses the button we have added below
// This function takes the contents of 'value' (the input from the user)
// and then sends this value to our server, which then sends a new request
// to the API
// The function then waits for the new response and updates the 'response'
// value which we then display on the page
const handleSubmit = async () => {
const response = await axios.post("http://localhost:3005/chatbot", {
question: value,
});
setResponse(response.data);
};

// In our return statement, we add an input field so that the user can ask
// questions to the API
// We also add a button so that the user can submit their question which then
// updates the response from the API
// We show the updated response on our page
return (
<div className="container">
<div>
<input
type="text"
value={value}
onChange={onChange}
></input>
</div>
<div>
<button onClick={handleSubmit}>Click me for answers!</button>
</div>
<div>
<p>Chatbot: {response}</p>
</div>
</div>
);
};

export default App;

We finally have some frontend functionality!

To see how it works so far, make sure your server is running then open a new terminal and run the development server with the following command: npm run dev

Finally, open your browser of choice and navigate to http://localhost:5173 where you should see the following (very ugly) UI:

chatbot running on local server

So… does it work? Let’s ask it a question…

chatbot response on local server

It works :) we essentially have our (pretty ugly) version of ChatGPT up and running, but that’s not even the coolest part…

We can customise our chatbot any way we want. I’m a huge Liverpool fan and so I’m going to customise my chatbot to be a fellow LFC fan who has a similar personality to one of my favourite players — Darwin Nunez.

This is where you can get creative and decide what type of ‘personality’ you want your chatbot to have. You can do this by editing the content of the "system” role in server.js:

// server.js

const response = await openai.chat.completions.create({
messages: [
{
role: "system",
content:
"You love Liverpool FC. Your name is Darwizzy and you have a
personality similar to Darwin Nunez
(a football player who currently plays for Liverpool).
You have Latin and Scouse humour.",
},
{
role: "user",
content: question,
},
],
model: "gpt-3.5-turbo",
max_tokens: 300,
});
res.send(response.choices[0].message.content);
});

So, how is it looking?

customised chatbot in React

Note: When you make changes in the server.js file, you’ll have to restart your server to see these changes. To avoid this, you can install nodemon with the following command: npm install -g nodemon
After this package is installed, restart your server with: nodemon server.js

Haha. I love it.

Time to make Darwizzy look a bit nicer.

Navigate to the App.css file and copy and paste the following code:

// App.css

* {
box-sizing: border-box;
text-align: center;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}

body {
background-color: rgb(39, 40, 41);
}

input {
width: 100%;
padding: 1em;
margin-bottom: 1em;
border: 0.15em solid #ccc;
border-radius: 0.25em;
font-size: 1.2em;
}

button {
width: 100%;
padding: 1em;
background-color: #d60000;
color: #fff;
border: none;
border-radius: 0.25em;
cursor: pointer;
transition: background-color 0.3s ease-in-out;
font-size: 1.2em;
box-shadow: 0 0.25em 0.25em rgba(0, 0, 0, 0.1);
}

button:hover {
background-color: #b20000;
}

p {
margin-top: 1em;
padding: 1em;
background-color: #ffffff;
border-radius: 0.25em;
font-size: 1.2em;
box-shadow: 0 1em 0.25em rgba(0, 0, 0, 0.1);
}

.container {
max-width: 35em;
margin: auto;
margin-top: 15em;
padding: 2em;
border-radius: 0.5em;
background-color: #f5f5f5;
}
simple chatbot app in React

You can see that I’m no UI/UX designer but it’s enough to get you started!

You did it! Well done! You’ve managed to integrate AI into a React app to create your own chatbot, which runs on a local server!

And it’s just the beginning. Now you have this solid foundation, you can customise the chatbot even more and develop the application even further :)

I hope you found this walkthrough useful and I’d love to hear your feedback!

--

--