Build a voice assistant with Craft CMS (Part 1)

Posted 20/8/2018 by Andrew Fairlie

Voice assistants are everywhere. They're taking over. Bit by bit they're replacing us, and I for one want to be on the robot's good side when they become our overlords.

So in this post I'll be showing you how to make a little voice assistant bot powered by Craft CMS.

This is the first of a four part series that will walk you through building a simple bot and then a more complex bot with contexts and multiple intents. It will end with a summary on how to publish the bot and get it in the hands (or voices?) of your users.

Introducing Dialogflow

Dialogflow is a service from Google that allows you to built conversational bots for Google Assistant and Amazon Echo. But it also lets you make Facebook Messenger, Twitter, and Slack bots too, so you can adapt this guide to work on pretty much any integration that Dialogflow supports.

Things to know

You need to be able to serve your Craft site on a publicly accessible URL protected by a signed SSL certificate.

In part 1 to keep things simple you'll need to disable CSRF protection in your config.php to allow Dialogflow to speak to our site. So be sure to do this in a safe environment. This is not advised to be done on a real life website, and we'll re-enable it in a later part.

These instructions are for Craft 3, but can be easily adapted for Craft 2. For example, in this part the only thing you'll need to change is .one() for .first()

Our plan

We're going to make a simple assistant that will return a random fact. "Tell me a random fact!"

Setting up Craft

Make a new channel called "Fact" with a text field, "fact". Add a few entries to the channel to get the ball rolling. Simple!

Making the feed

Dialogflow will need to speak to our website to get the information, so we'll need to make a new Twig file to reply with JSON.

We'll call this file /api/random-fact.json

Setting up Dialogflow

First up, make your free Dialogflow account by going to the Dialogflow Console.


  1. Make a new agent. Saving might take a while, it's okay for it to hang on "Working..." for a while.
  2. You'll see that by default it'll have a welcome intent and a fallback intent.
  3. On the right hand side on the "Try it now", write or say "Hello" and you'll see the default welcome intent kick in.

Dialogflow listens to the user's voice and finds the most appropriate 'intent' for it. An intent are really just different kinds of questions. For example, a cinema might have the following intents...

  • How do I get to the cinema?
  • What is showing tonight?
  • What time is "The Robot Uprising" playing?

Firstly we need to enable the webhook. You can do this by...

  1. Go to "Fullfillment" on the left sidebar
  2. Next to the webhook title, turn the lightswitch to "Enabled".
  3. It'll reveal additional fields, in the URL field add our new JSON feed URL
  4. Press "Save" at the bottom of the screen

Now that we have our webhook...

  1. Press "+" next to "Intents" on the left sidebar
  2. Call this intent "Random Fact".
  3. Press "Add training phrases"
  4. Add phrases to activate this intent, like "tell me a fact", "tell me a random fact", or "fact me up". Dialogflow uses machine learning to understand additional phrases once you've trained it with what you expect people to say.
  5. On the "Fulfillment" section of this screen, press "Enable Fulfillment" and then turn both "Enable webhook call for this intent" and "Enable webhook call for slot filling" to to enabled
  6. Press "Save"

That's it!


On Dialogflow's right hand sidebar, you can press "See how it works in Google Assistant" to test the app.

You will first need to say "Talk to my test app" and then you can say "Tell me a random fact", "Fact me up!" or any other training phrase you gave it.

Have fun and play with the machine learning. Say something like "Give me a fact, you robot scum".

For now we're in charge, so it will probably answer you, but be careful, once they take over that kind of language won't fly.

Next up

  • Part 2: Handling multiple intents
  • Part 3: Enabling CSRF protection
  • Part 4: Contexts and publishing

Follow us on Twitter @madebymutual to get notified as the next parts get released over the next few weeks.

More musings