Posted on Leave a comment

Building an advanced restaurant delivery chatbot with Google Sheets integration

AC tips - building advanced restaurant chatbot

Building an advanced restaurant delivery chatbot with Google Sheets integration

Highly customizable chatbot in less than 2 hours


  •  Slide Item 4
Device Slider
This complete walk-through will teach you how to use Google Sheets integration in your chatbots. See how easy it is to build highly customizable chatbots for complex use cases with the power of Activechat. 

Table of content

Setting the goals

Let’s start with complete list of features for this simple chatbot. Since it’s not a production-ready solution, but rather an illustration of Google Sheets integration mechanics, there will definitely be some shortcuts. Feel free to use the template for your own design!

We’ll use a simple Google Sheets spreadsheet to store chatbot data. One sheet will contain complete list of products that are available for delivery, and another will hold orders from chatbot users. 

Click to see actual data here 👉 Restaurant delivery chatbot Google Sheets template

You can test the sample bot here 👉 Activechat Pizza Bot v.2

It’s supposed that there will be a bot admin, receiving new delivery orders, sending couriers and marking orders as delivered.

Here is the complete list of features for this simple chatbot:

  • Display a gallery of products from specific category based on certain search criteria
  • Display detailed information about specific products
  • Take delivery orders, send order notifications to admin’s email and store orders in the Google Sheets document
  • Allow users to check the status of their order and leave comments for couriers

Designing chatbot skills

designing chatbot skills

This chatbot is very simple, so it will have just a few simple skills. The complete development process should  take around an hour only.

First, we’ll have the “start” skill to greet the user and offer him/her some options. 

Next, we’ll have a “menu” skill, displaying the gallery of products that fit user’s search criteria. 

To process delivery orders, we’ll need the “order” skill. 

Another skill will be used to check the status of user’s order and add comments to orders that are not yet delivered. Let’s call it “status”.

These skills will be inter-connected with events, and “default” skill will trigger other skills based on the keywords detected in user’s message.


Preparing the data

Google Spreadsheet for restaurant delivery chatbot
Google sheet with restaurant menu for the chatbot (click to enlarge)

Our chatbot will be extremely flexible in terms of product catalogue. We’ll store everything in a Google spreadsheet, one product per row, with columns for:

  • Product ID
  • Product category (used for filtering)
  • Product name
  • Product description
  • Product price
  • Product weight
  • Link to product image
  • Product availability (a simple Yes/No)

Chatbot admin will be able to add more products and product categories easily, and disable product availability with a simple change of “Yes” to “No”  in a spreadsheet cell.

Google sheet with orders from delivery chatbot
Google Sheet with the list of chatbot orders (click to enlarge)

Delivery orders will be stored in another sheet of the same spreadsheet. For each order (one per line) we’ll put there:

  • Messenger ID of chatbot user
  • His (her) name, e-mail and phone number
  • Order date and time
  • Order cost
  • Name of the product ordered
  • Delivery address
  • Order status (“waiting”, “preparing”, “cooking”, “packing”, “delivering”, “done”, edited by admin)
  •  Estimated delivery time (edited by admin)
  • Link to product image (we’ll use this in the next chapter to display the gallery of previous orders for specific user)
  • User’s comments for this order (like, address details, extra add-ons etc).

Starting the conversation

Our “start” skill will be very simple. It will display “Choose something from our menu” message and then it will listen to user’s choice, displaying two quick replies – “pizza” and “salad”. Once user clicks one of these replies (or types anything else), “start” skill will continue to the SEND block, triggering “menu2” skill to display the menu.

"Start" chatbot skill
"Start" chatbot skill

Instead of clicking “pizza” or “salad” quick replies, user can type something else – for example “dessert”. If there’s anything in “desert” category in your Google Sheet, then these products will be displayed. LISTEN block is saving user’s input to the $search bot attribute, which is used in the next skill.


Now comes the fun part. We have product category in the $search attribute, and we want to display a gallery of products from our Google Sheet that relate to that category. Something that would require advanced coding in any other chatbot platform can be done in Activechat with just a couple of blocks. 

ℹ️ When working with dynamic galleries you should keep in mind Facebook’s limitations on gallery size – it’s limited to 10 scrollable cards. To make chatbot conversation flexible and able to display unlimited number of products we’ll use a simple navigation trick. 

GS-GALLERY block will do a search on your Google Sheet and display a gallery of cards that fit the search criteria. Let’s look into this in more detail. 

Dynamic Google Sheets gallery
Dynamic Google Sheets gallery (click to enlarge)

Once you connect your Activechat to your Google Account (go to Settings – Integrations – Google to do this), you can use GS-GALLERY block to build dynamic galleries from any spreadsheet. The block in the example above contains three self-explanatory parts:

  1. Set search criteria. In this example we’ll build the gallery from rows where column B (product category) is equal to $search attribute value (remember – we got this value from the user in our “start” skill?) and column H (product availability) is equal to “Yes” (means, the product is available for delivery).
  2. Build gallery content. We’ll use column C (product title) as Title for each gallery card, column D (product description) as card’s Subtitle and column G (product image) as image URL. 
  3. Add extra attributes to each card. We’ll add value from column E (product price) to “price” gallery attribute and column F (product weight) as “weight” gallery attribute. Later, when user clicks any of the gallery buttons, these values will be available as $_selected_gallery_price and $_selected_gallery_weight bot attributes (note the naming convention – we just add $_selected_gallery_ to the attribute name). 
To each of these cards we’ll add two buttons – one to order the displayed product (it will trigger the “order” skill) and another to display detailed information about the product.
Adding buttons to dynamic Google Sheets galleries
Adding buttons to dynamic Google Sheets galleries (click to enlarge)

These buttons will be added to each card in the gallery. Once the user clicks any of these buttons, chatbot will continue to the connected block, while setting a number of attributes to values defined by the card content:

  • $_selected_gallery_title will contain the “Title” field of the card
  • $_selected_gallery_subtitle will contain the “Subtitle” field
  • $_selected_gallery_image will contain the image link for that card
  • $_selected_gallery_<attribute> will contain any extra card attributes that you added in the “Attributes” part of GS-SEARCH

This gives your chatbot the ability to know which card was clicked, and you can use that data in the conversation that follows.

For example, when user clicks “Details” button, we want to display detailed info about the selected product. Note the use of dynamic gallery attributes in TEXT and IMAGE blocks that are connected to this button:

Using dynamic gallery attributes
Using dynamic gallery attributes (click to enlarge)

TEXT block that displays detailed product description from $_selected_gallery_subtitle contains two buttons. “Show more” will go back to the GS-GALLERY block, displaying the same gallery again, and “New search” will ask user for new search criteria.

Note the use of card attributes to display extra data (not available as card Title or Subtitle) in the detailed description. This allows you to store extra parameters with each gallery card, and these card-specific parameters can be used in the conversation when user clicks the card in the gallery:


Detailed info from card attributes
Detailed info from card attributes and the "New search" button (click to enlarge)

Navigating multiple gallery pages

Let’s see what happens if there’s more than 10 rows in your spreadsheet that fit GS-SEARCH block search criteria. Once this block is executed (and gallery built) you will have two system attributes to check the number of search results:

  • $_gs_total_results will contain total number of spreadsheet rows that fit your search criteria
  • $_gs_total_pages will contain the number of results divided by 10 (efficiently, the number of 10-card galleries required to display all search results)
We can check the value of $_gs_total_pages to see if there’s more than one gallery page and build a simple page navigation mechanics with quick replies:
Chatbot navigation for multiple pages in gallery
Chatbot navigation for multiple pages in gallery (click to enlarge)

What’s going on here? 

Immediately after we display the dynamic gallery with products, we check the value of $_gs_total_pages with SWITCH block. If it’s less than 2 (i.e. we have only one page of search results) we do nothing (notice that there’s no block connected to that exit in SWITCH). But if it’s 2 or more, we proceed to another SWITCH with three different options:

  • if current page number (we store it in $page attribute and set to 1 before displaying the gallery) is 1, we show “Use buttons to navigate” message and display a single quick reply for “Next page”
  • if current page is greater than 1 and less than $_gs_total_pages (i.e. the maximum page number possible for that search), we display two quick replies for navigation – “Previous page” and “Next page”
  • and, finally, if current page is equal to the maximum page number we display just a single quick reply – “Previous page”
Once the user clicks “Previous page” or “Next page” quick reply, we decrease or increase the current value of $page attribute by 1 and go back to GS-GALLERY block to display search results again, starting from the specified page:
Displaying specific page in dynamic gallery
Displaying specific page in dynamic gallery (click to enlarge)

Receiving delivery orders

What happens when chatbot users click the “Order” button in our dynamic gallery or in detailed product view? Let’s see how the bot is sending these orders to the Google spreadsheet. 

Collecting lead data with the chatbot
Collecting lead data with the chatbot (click to enlarge)

This flow is very simple. The bot is asking user a couple of questions like email, phone number and delivery address, and then sends this data to bot admin with the LEAD block and stores it to Google Sheets with GS-UPDATE block. When this is done, the bot displays “You’re all set” confirmation message and two quick replies to check pizzas or salads again.

LEAD block is combining user’s details and order data into a neat email message that is sent automatically to admin’s address.

Sending lead data to bot admin
Sending lead data to bot admin (click to enlarge)

After this, we proceed to GS-UPDATE block to store the order into Google Sheets. 

Storing data into Google Sheets with GS-UPDATE
Storing data into Google Sheets with GS-UPDATE (click to enlarge)

Notice – I’m setting “Insert” parameter to “true” and use “2” as the row number. It will instruct Activechat to add new rows above row 2, so that the latest orders are always on top of our spreadsheet (row 1 is reserved for column headers).

Cell values are obtained from attributes that the chatbot already has:

  • “User ID” (column A) – from $_id system attribute
  • “User name” (column B) – from  $_first_name and $_last_name system attributes
  • “E-mail” and “Phone” (columns C and D) – from lead data that we collected with LISTEN blocks ($user_email and $user_phone)
  •  “Order date” (column E) – from $_year, $_month, $_date system attributes (current date)
  • “Order time” (column F) – from $_hour, $_minute, $_second system attributes (current time)
  • “Order price”, “Order content” (columns G, H) – from $_selected_gallery_price and $_selected_gallery_title attributes that were set automatically when user clicked a button in the dynamic gallery
  • “Delivery address” (column I) – from $user_address attribute collected by LISTEN block 
  • “Order status” (column J) – set by default to “received”. This can be changed later in the Google Sheets document by bot admin and updated statuses will be displayed to the user.
  • “Delivery time” (column K) – set to “estimating..” by the bot. Once admin reviews the order, he/she can change the value in that cell to be displayed to user on every status check.
  • “Image” (column L) – from $_selected_gallery_image attribute set when user clicked a button in the dynamic gallery. This column is not used in the current version of the bot, but we’ll be using it later to display the gallery of previous orders
  • “Comment” – empty, the bot will be updating that column later, in the “status” skill.

Checking order status

Let’s make it possible for our chatbot users to check the current status of their order (remember we have “Status” column in our Google Sheet which is supposed to be updated by bot administrator?). 

The logic will be quite simple: once the user requests the status check, we’ll find a row in the Google Sheet with his (her) Messenger ID in column A and anything except “done” in column J (“Order status”) and display the status. It is supposed that at every moment there can be only one (or none at all) order in any other status – this can cause problems if user is placing multiple orders before admin changes their status to “done”. You can fix it with a simple check before accepting new order – just use a similar GS-SEARCH to check for open orders placed by the same user. Adding this check will be your homework assignment! 😁   

Searching for data in Google Sheets
Searching for data in Google Sheets (click to enlarge)

When this skill is triggered, the bot sends “Hold on, checking my records” message first and then we use GS-SEARCH to find a spreadsheet row where column A (user ID) is equal to the current user’s Messenger ID (it’s available in the $_id system attribute).

After GS-SEARCH is executed, we’ll check the value of $_gs_result system attribute. If it contains “This value was not found” (actually, I’m checking only for “not found”), it means that there are no active orders for that customer, and the bot is sending “It looks like there are no active orders from you currently”.

But if the value of $_gs_result is “Ok” – it means that the row was found, and we can update user with information from that row. So, the bot proceeds to the TEXT block:

Using values from Google Sheets in the TEXT block
Using values from Google Sheets in the TEXT block (click to enlarge)

This block is displaying data from Google Sheets row that the bot have found on the previous step. Notice the use of $_gs_<column> attributes – they are populated automatically after every successful search and contain values from every column in that row. That means that column A value will be available as $_gs_a, column B – as $_gs_b etc.

Adding comments to orders

You may have noticed “Add comment” button in the TEXT block that displays order status. I’ve added it to allow chatbot users to leave comments for their orders (for example, how to get to the building, adding extras to the order or anything else). 

When user clicks that button the bot says ” Sure, just type and send” and LISTENs to user’s input, saving it to the $order_comment attribute. Once the user send his/her comment, the bot proceeds to GS-UPDATE block, adding that comment to column M in our spreadsheet (and overwriting previous value in that column, if any).

Updating column value with GS-UPDATE block
Updating column value with GS-UPDATE block (click to enlarge)

We’re using the value of $_gs_row attribute to specify which row in the spreadsheet should be updated. This attribute always contains row number of the last successful execution of GS-SEARCH block.

Notice that “Insert” option in the GS-UPDATE block editor is set to “false”. This instructs Activechat to update the existing spreadsheet row instead of adding new one. on top When we were accepting orders above, we set this parameter to “true” so that new orders would be piled on top of your spreadsheet.

Triggering skills with keywords

How does the user triggers these skills and how does the bot know which skill to use? 

To make it possible we’ve introduced a very simple keyword detection in the “default” skill. For a quick recap – this skill will be triggered every time when user is sending message to your chatbot and you do not have any LISTEN block actively listening to user’s response (i.e. the bot is in “idle” mode).

Keyword detection with the "default" skill
Keyword detection with the "default" skill (click to enlarge)

We’re using SWITCH block to check the value of $_last_user_input system attribute (it always contains the last message that user sent to the chatbot).

If this attribute contains “pizza” or “salad” or “deliver” (the user asked something like “how to order delivery?” or “I want pizza” etc), the bot will trigger “start” skill again (since the ordering starts in that skill, with “Choose something from our menu” message).

If $_last_user_input contains words like “order” or “where” or “status” (for example, user is asking “Where is my order?” or “What’s my order status?”), the bot will trigger “status” skill (see above).

Please keep in mind that SWITCH block is evaluating conditions top to bottom, in the order they appear in the block editor. So, if you’re checking for “deliver” keyword first (to answer questions like “How do you deliver?”) and then for “delivery” keyword (to answer “Where is my delivery?”) you should be aware that both phrases will trigger the first condition because “delivery” contains “deliver” as sub-string. 


It looks like we’ve managed to build quite complex chatbot which is almost ready to be used in real-life application. Bot admin will be able to add new products and categories easily, adding new rows to Google spreadsheet. Admin will receive orders, update statuses and estimated delivery times and mark orders as “done” on delivery, and chatbot users will be able to browse products, make orders, check order statuses and leave comments.

It took us less than an hour to build that chatbot, and it’s just 5 skills with 58 blocks in total. Imagine doing something similar with Manychat or Chatfuel! 

You can test the sample bot here 👉 Activechat Pizza Bot v.2

You can experiment, customize and improve that bot from the template – look for “Activechat Pizza Bot v.2” in our chatbot templates

Chatbot templates in Activechat
Chatbot templates in Activechat

There are many improvements to make, of course. Throwing in a couple of extra blocks will add the ability to send instant in-Messenger notifications to bot admins or arrange direct communication between customers and delivery couriers right in the chatbot – we’ll be covering these and many other cool features of Activechat in the next walk-through sessions like this!

Did you like it? Just let me know in the comments on our Facebook community

Did you find this useful? Please share with other bot builders!


© 2018-2020 Activechat, Inc.

existing users

Posted on Leave a comment

Chatbot buttons vs quick replies

Chatbot buttons vs quick replies

Two basic approaches to chatbot navigation


A lot of people seem to be confused by two chatbot interaction elements that are available on every messaging platform – buttons vs quick replies. 
buttons vs quick replies
Example of e-commerce chatbot conversation using both buttons and quick replies

Chatbot navigation

Majority of chatbots built with modern low-code chatbot platforms are based on decision trees. Natural language understanding chatbots are still quite difficult to build and train.

Decision tree chatbots are using two basic types of interactive elements – buttons and quick replies – to navigate through various bot features and conversation parts.

Let’s look into details to see how these elements can be used!


Chatbot buttons

On most messengers (like Facebook Messenger or Telegram) buttons can be attached to specific messages that the chatbot is sending to users – texts, images and galleries (carousels). In the example above there are three buttons attached to “Pick an option below to get going” message in the CNN chatbot

Buttons are displayed as a small menu and are usually limited to 3 options. Maximum length of the button name (the text that is displayed on the button) is 20 characters on Facebook Messenger. 

A lot of chatbot designers are adding smileys to button names to make it more visually appealing and easy to understand.

Depending on the chatbot design, buttons can trigger specific parts in the chatbot flow (send events or postbacks), open website pages or initiate phone calls on mobile devices. 


Quick replies

Quick replies (or chips as Google calls it) are pre-defined responses that chatbots offer to their users. They are displayed as bubbles next to the message typing area, and users can click one of the replies instead of typing it in. 

Some messenger platforms like Facebook Messenger or Telegram allow bots to pre-populate quick replies with user-specific data like email or phone number, so that user can click this reply and share the information with the chatbot immediately, no need to type it manually. 

You can use up to 13 quick replies on Facebook Messenger, but usually it makes sense to limit the number to 3-5. It’s plain common sense and good conversational design – trying to keep things as simple as possible to make interaction with your chatbot easy.


Using buttons and quick replies

Example of buttons in the chatbot
Example of chatbot buttons (click to enlarge)

On Activechat visual chatbot builder you can add buttons to blocks from TALK category (TEXT, IMAGE and GALLERY) and also to e-commerce blocks (automated category and product galleries).

Example above shows a simple pizza chatbot that greets the user and asks “What would you like to order?”, offering two connection buttons for pizzas or salads. When the user clicks one of these buttons, the flow will continue from the block that is connected to it.

Please note that there’s no LISTEN block connected to the TEXT block with buttons. It means that if user types anything instead of clicking one of these buttons, the chatbot’s “default” skill will be triggered – use some type of keyword detection there to be able to respond to that message.

There are four common button types:

  • Connection button
  • Event button
  • URL button
  • Phone call button

Connection and event buttons are used to branch the conversation according to user’s choice. URL button will open a webview with the web page at the specified address, and phone call button will initiate a phone call where it’s supported (mostly on mobile devices).  

Example use of quick replies in the chatbot
Example of chatbot quick replies (click to enlarge)

This example shows how you can achieve exactly the same functionality with quick replies instead of buttons. Please note that now we’re using LISTEN block. It means that after “What would you like to order?” message your chatbot will be actively listening to user’s response, showing two quick reply bubbles for pre-defined options. 

If user clicks one of these quick replies (or exactly types the text on the quick reply, i.e. “pizza” or “salad”), the bot will save the response text to $choice attribute (as indicated in the LISTEN block editor) and the flow will continue to the block that is connected to that reply. If user types anything else, the flow will continue from the bottom of LISTEN block. We’ve connected another message there, saying “Please make a choice!” and looping back to the same LISTEN block, displaying the same two quick replies.

Feel free to reproduce these skills in your own Messenger chatbot and check how it works.


Connections vs event buttons

Connection buttons are used… well, to connect other blocks. It’s ok to do so in simple chatbot skills, where different conversation branches can be implemented in just a couple of extra blocks.

If your button should start a complex conversation, it makes sense to implement it as a separate skill, triggered by event, and use event button to start it.  

Example of event (postback) buttons
Example of event (postback) buttons (click to enlarge)

In the example above we’re using two event buttons, one to trigger “manuals” event (and thus start a “/manuals” skill) and another to trigger “faq” event. 

When using this type of buttons, you should have CATCH block somewhere in one of your chatbot skills, listening to these events.

Common mistakes

Good conversational design is not easy, and sometimes chatbot developers mess up with buttons and quick replies in the variety of ways. Let’s look into most common mistakes (try to avoid it!)


1. Nothing is connected to the button

Example of missing button connection

Guess why connection button is marked with yellow in the example above? It’s a warning that there are no blocks connected to that button, so if your chatbot user clicks it in the conversation nothing will happen.  


2. No matching CATCH block for event button

event buttons
Example of missing button connection

If you’re using “event” type buttons, make sure that somewhere in your chatbot there is a CATCH block listening to that event. Otherwise nothing will happen when user clicks on these buttons.


Buttons and quick replies use cases

To make a long story short, here are some recommendations on what type of interaction to use in various situations:

  • If you need to save user’s choice as bot attribute, use LISTEN block and quick replies
  • If your conversation is simple, use connection type buttons
  • If you need to trigger complex bot skills, use event type buttons
  • If you need to get user’s email or phone number, quick replies are the only option


Do you find this useful? Click to share with other bot builders!


© 2018-2020 Activechat, Inc.

existing users