# (Tutorial) Make a sample reply bot using Node.js

Messaging API is a feature that enables two-way communication between your service and LINE users.

Using Messaging API, you can boost interactions with users by taking advantage of a wide range of functions that it offers. These functions include sending various types of messages, getting user profiles, getting content sent by users, and many more.

This tutorial explains how to send a message through Messaging API using Node.js.

# Goal

At the end of this tutorial, you'll have created an app which automatically responds to a message sent by a user.

Conversation with a sample bot

# Before you start

There are some concepts and tools that you may want to learn before starting this tutorial.

This tutorial doesn't use the SDK

For the purpose of learning and maximum customizability, this tutorial shows you how to use Messaging API with Node.js without using an SDK provided by LINE. If you want to use the Messaging API quicker and with fewer lines of code with Node.js, we recommend using LINE Messaging API SDK for nodejs (opens new window).

# Assumed technical knowledge

This tutorial requires basic knowledge of JavaScript and Node.js.

# Messaging API concept

To smoothly follow this tutorial, we recommend that you read Messaging API overview.

# What you'll need

Heroku's free plan has been discontinued

Heroku's free plan has been discontinued as of November 27, 2022. If you would like to try this tutorial for free, use another platform. For more information, see Heroku’s Next Chapter (opens new window).

To create this app, you will need these tools installed or registered:

# Set up Heroku

Let's first set up a Heroku environment.

Run this command and log in to the Heroku CLI. Open a terminal or command line tool.

heroku login

Run this command in a location where you want to make the app to create a new directory, initialize Git, and create a new app using Heroku.

mkdir sample-app
cd sample-app
git init
heroku create {Name of your app}

For {Name of your app}, enter a unique name. For example, msg-api-tutorial-{YYYYMMDD}.

If the creation is successful, the Heroku URL will be generated in this format: https://{Name of your app}.herokuapp.com/. You'll need this URL later, so take a note of it.

Try accessing the Heroku URL that was just created in your browser. You should see a welcome page.

Welcome page

# Create a package.json file

To allow npm to identify your project, hold the project's metadata, and handle its dependencies, create a package.json file. In the root directory of your project, run this command:

npm init -y

npm init initializes your npm package. We use the -y command to skip all of the questions asked to set up the package, as no special configuration is required for this tutorial.

You should see something like this:

{
  "name": "sample-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

We also need to add a start script, so that a server platform like Heroku will know which file to use when starting the server. In this tutorial's case, we need to specify index.js as our server configuration file.

Add "start": "node index.js" to package.json:

{
  "name": "sample-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",  
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Additional packages installed for this project are managed in package.json. In this project, we'll use this package:

Install this package by running this command:

npm install express

When Express.js is installed, a directory named node_modules will be created. This directory will contain the packages that were installed locally.

To prevent this directory from being pushed to Heroku, we create a .gitignore file.

touch .gitignore

Open the .gitignore file you created with a text editor. In .gitignore, add the following:

node_modules/

# Start developing

# Global configuration

Let's create a new server configuration file called index.js.

touch index.js

Open the index.js file you just created in an editor. In index.js, add:

const https = require("https")
const express = require("express")
const app = express()

Here, we instantiate express after importing the express package we just installed and the https package. https is the package that will be used to handle HTTP requests for this app. This package comes with Node.js by default, so there is no need to install it like the express package.

Now add the required environment variables to the file.

Environment variables are variables whose values are set outside of the program. In this tutorial, environment variables will be used to simplify the configuration process and prevent credential information from being accidentally exposed.

In index.js, underneath the imported packages, add:

const PORT = process.env.PORT || 3000
const TOKEN = process.env.LINE_ACCESS_TOKEN

process.env.PORT specifies which port the server should listen to. process.env.LINE_ACCESS_TOKEN specifies the channel access token required to call the Messaging API.

# Configure middleware

Express.js is a middleware web framework. Middleware functions determines the flow of request-response cycle.

In this tutorial, we'll use express.json() and express.urlencoded(), which are pre-defined middleware functions in Express.js to recognize the incoming request objects as JSON, and string or arrays, respectively. To load the middleware functions, call app.use(). In index.js, add:

app.use(express.json())
app.use(express.urlencoded({
  extended: true
}))

# Configure routing

Now let's add a basic routing logic to our bot server. As a best practice, we should send a status 200 when a HTTP GET request is sent to the root (/) of our domain to prevent health check failures.

To do this, add this to your index.js file:

app.get("/", (req, res) => {
  res.sendStatus(200)
})

A "listener" is also needed to start the server. We'll use the app.listen() function to specify the port for the server to listen to. Since we've set up the PORT environment variable, it will listen to 3000, unless otherwise configured.

In index.js, add:

app.listen(PORT, () => {
  console.log(`Example app listening at http://localhost:${PORT}`)
})

When a user interacts with your bot, the LINE Platform server sends an HTTP POST request to the webhook URL, which is hosted by your bot server.

app.post() routes the HTTP POST requests to the path you specify. Use this function to configure how the bot server responds to these requests.

In index.js, between app.get() and app.listen() functions, add:

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
})

This tells the bot server to return the HTTP response HTTP POST request sent to the webhook URL! when a HTTP POST request is sent to the /webhook endpoint.

So far, your index.js should look something like this:

const https = require("https")
const express = require("express")
const app = express()
const PORT = process.env.PORT || 3000
const TOKEN = process.env.LINE_ACCESS_TOKEN

app.use(express.json())
app.use(express.urlencoded({
  extended: true
}))

app.get("/", (req, res) => {
  res.sendStatus(200)
})

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
})

app.listen(PORT, () => {
  console.log(`Example app listening at http://localhost:${PORT}`)
})

Now set up a reply for when an end user sends a message.

Because we want to respond to users' messages, we need to detect when users send a message. When a user sends a message to your bot, a message event object is sent to the webhook URL. The message event contains a type property, which is set to message. We can use this message to identify that the incoming webhook event object is of the message type.

To send a reply to the user, use the Send reply message endpoint (https://api.line.me/v2/bot/message/reply).

In app.post in index.js, add:

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
  // If the user sends a message to your bot, send a reply message
  if (req.body.events[0].type === "message") {
    // Message data, must be stringified
    const dataString = JSON.stringify({
      replyToken: req.body.events[0].replyToken,
      messages: [
        {
          "type": "text",
          "text": "Hello, user"
        },
        {
          "type": "text",
          "text": "May I help you?"
        }
      ]
    })

    // Request header
    const headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + TOKEN
    }

    // Options to pass into the request
    const webhookOptions = {
      "hostname": "api.line.me",
      "path": "/v2/bot/message/reply",
      "method": "POST",
      "headers": headers,
      "body": dataString
    }

    // Define request
    const request = https.request(webhookOptions, (res) => {
      res.on("data", (d) => {
        process.stdout.write(d)
      })
    })

    // Handle error
    request.on("error", (err) => {
      console.error(err)
    })

    // Send data
    request.write(dataString)
    request.end()
  }
})

Let's break down this code.

First we define reply token and the reply message data that we send to the API server in JSON format and stringify it in the dataString variable.

headers specifies the required properties for the request header.

We also define options that we pass into the request in the webhookOptions variable. webhookOptions takes options that follow the specifications defined in the https.request (opens new window) method in the Node.js documentation, such as the endpoint hostname and path, HTTP request method, headers, and body.

const dataString = JSON.stringify({
  replyToken: req.body.events[0].replyToken,
  messages: [
    {
      "type": "text",
      "text": "Hello, user"
    },
    {
      "type": "text",
      "text": "May I help you?"
    }
  ]
})

const headers = {
  "Content-Type": "application/json",
  "Authorization": "Bearer " + TOKEN
}

const webhookOptions = {
  "hostname": "api.line.me",
  "path": "/v2/bot/message/reply",
  "method": "POST",
  "headers": headers,
  "body": dataString
}

When an HTTP POST request of message type is sent to the /webhook endpoint, we send an HTTP POST request to the https://api.line.me/v2/bot/message/reply endpoint to send a reply message.

Set up the request by defining a request variable:

const request = https.request(webhookOptions, (res) => {
  res.on("data", (d) => {
    process.stdout.write(d)
  })
}

request.on is a function that is called back if an error occurs while sending a request to the API server.

request.on("error", (err) => {
  console.error(err)
})

Finally, we send the request defined in previous lines, when this code is executed:

request.write(dataString)
request.end()

Your final code should look something like this:

const https = require("https")
const express = require("express")
const app = express()
const PORT = process.env.PORT || 3000
const TOKEN = process.env.LINE_ACCESS_TOKEN

app.use(express.json())
app.use(express.urlencoded({
  extended: true
}))

app.get("/", (req, res) => {
  res.sendStatus(200)
})

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
  // If the user sends a message to your bot, send a reply message
  if (req.body.events[0].type === "message") {
    // Message data, must be stringified
    const dataString = JSON.stringify({
      replyToken: req.body.events[0].replyToken,
      messages: [
        {
          "type": "text",
          "text": "Hello, user"
        },
        {
          "type": "text",
          "text": "May I help you?"
        }
      ]
    })

    // Request header
    const headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + TOKEN
    }

    // Options to pass into the request
    const webhookOptions = {
      "hostname": "api.line.me",
      "path": "/v2/bot/message/reply",
      "method": "POST",
      "headers": headers,
      "body": dataString
    }

    // Define request
    const request = https.request(webhookOptions, (res) => {
      res.on("data", (d) => {
        process.stdout.write(d)
      })
    })

    // Handle error
    request.on("error", (err) => {
      console.error(err)
    })

    // Send data
    request.write(dataString)
    request.end()
  }
})

app.listen(PORT, () => {
  console.log(`Example app listening at http://localhost:${PORT}`)
})
Verify the signature if you want to publish the bot for production use

Signature verification is necessary when you publish this sample bot for production use to an unspecified number of users. Verify the signature in the request header x-line-signature to confirm HTTP requests were sent from the LINE platform.

For more information on how to verify signatures, see Verifying signatures in the Messaging API documentation.

# Prepare a Messaging API channel

To use Messaging API features, you need to create a Messaging API channel and register your webhook URL.

To create a Messaging API channel, follow the instructions in Creating a channel on the LINE Developers Console.

In the Messaging API channel you created, under the Messaging API tab, issue the channel access token.

Channel access token section in a Messaging API channel

In the Messaging API tab, fill Webhook URL with the Heroku URL you obtained in the Set up Heroku section, using this URL format: https://{Name of your app}.herokuapp.com/webhook. Note that Webhook URL is not https://{Name of your app}.herokuapp.com/.

If you've forgotten your Heroku URL

If you've forgotten your Heroku URL, you can check it in the Heroku Dashboard (opens new window).

Enable Use webhook by toggling the slider to the right.

"Enable webhook" setting in Messaging API tab

Add the LINE Official Account associated with your bot as a friend on LINE by scanning the QR code on the Messaging API tab.

Disable Auto-reply messages and Greeting messages.

Now your Messaging API channel is ready!

# Deploy on Heroku

In the Global configuration section, we've set the environment variable LINE_ACCESS_TOKEN to be used as the channel access token. The environment variable LINE_ACCESS_TOKEN needs to be registered for the app deployed on Heroku to work properly.

In your terminal or command line tool, using the channel access token you obtained in Prepare a Messaging API channel, execute:

heroku config:set LINE_ACCESS_TOKEN={enter your channel access token here}

Now your app is ready to deploy!

In your terminal or command line tool, execute these commands to push your code to Heroku:

git add .
git commit -m "First commit"
git push heroku master

# Verify webhook URL

Let's now verify that the webhook is working properly.

Click the Messaging API tab in the channel you created in Prepare a Messaging API channel.

Click Verify in Webhook URL to verify that the webhook is working properly.

If there is no problem with the Webhook URL, a "Success" message will be displayed. If there is a problem, an error message will be displayed.

If you see a "Success" message, your sample bot is finished!

Try sending a message to the bot on your LINE app. You should receive a message like this:

Conversation with a sample bot in the LINE chat room

# Troubleshoot the sample bot

If your bot isn't working properly, you can see the Heroku log by executing this command:

heroku logs --tail

# Further development

There are a number of features you can add to this bot, such as:

  1. Send a Rich menu to show tappable options to the users.

  2. Trigger a response based on the action object sent when a user performs a certain action.

  3. Get user profile to send a customized message.

As mentioned previously, LINE Messaging API SDK for nodejs (opens new window) provides a quicker way to build a bot. Consider trying it out!

# References