Build your conversational Action (Dialogflow)

You define the conversation for your Action with fulfillment, which is code deployed as a webhook that contains your Dialogflow agent's conversational logic. Fulfillment tells your Action what to do when users make requests.

For Interactive Canvas, your fulfillment also communicates information about your web app to the Assistant. You can use an HtmlResponse to tell the Assistant to render your web app. An HtmlResponse can also provide updates to data, which your web app custom logic uses to make changes to your web app.

This page goes over how to use HtmlResponse in your fulfillment and general guidelines for using this response type.

HTML responses

To relay information about your web app to the Assistant, you must include an HtmlResponse in your intent-specific fulfillment. An HtmlResponse can contain the URL of the web app and data that updates the web app. When you send an HtmlResponse, the following steps occur:

  1. The fulfillment of the matched intent sends an HtmlResponse to the device.
  2. The device uses the URL in the HtmlResponse to load the web app.
  3. The data JSON payload is passed to the web app in a callback.
  4. Your conversational Action sends a new HtmlResponse to send updates or load new states.

Sample fulfillment

The following excerpt from the sample fulfillment code shows how to implement HtmlResponse:

const functions = require('firebase-functions');
const {dialogflow, HtmlResponse} = require('actions-on-google');

const app = dialogflow({debug: true});
app.intent('welcome', (conv) => {
  conv.ask('Welcome! Do you want me to change color or pause spinning?');
  conv.ask(new HtmlResponse({
    url: 'https://your-web-app.com',
  }));
});

// map of human speakable colors to color values
const tints = {
  red: 0xFF0000,
  green: 0x00FF00,
  blue: 0x0000FF,
};
app.intent('color', (conv, {color}) => {
  if (color in tints) {
    conv.ask(`Ok, I changed my color to ${color}. What else?`);
    conv.ask(new HtmlResponse({
      data: {
        tint: tints[color],
      },
    }));
    return;
  }
  conv.ask(`Sorry, I don't know that color. What else?`);
  conv.ask(new HtmlResponse({
    data: {
      query: conv.query,
    },
  }));
});
app.intent('start', (conv) => {
  conv.ask(`Ok, I'm spinning. What else?`);
  conv.ask(new HtmlResponse({
    data: {
      spin: true,
    },
  }));
});

app.intent('pause', (conv) => {
  conv.ask(`Ok, I paused spinning. What else?`);
  conv.ask(new HtmlResponse({
    data: {
      spin: false,
    },
  }));
});

app.intent('restart game', (conv) => {
  conv.ask(new HtmlResponse({
    data: {
      command: 'RESTART_GAME',
    },
  }));
});

exports.conversation = functions.https.onRequest(app);

welcome intent

In the snippet above, the fulfillment for the welcome intent sends an HtmlResponse with the URL for the web app. The Assistant receives this and loads the HTML and JavaScript at that address.

...
app.intent('welcome', (conv) => {
  conv.ask('Welcome! Do you want me to change color or pause spinning?');
  conv.ask(new HtmlResponse({
    url: 'https://your-web-app.com',
  }));
});
...

Other intents

The HtmlResponse in the fulfillment for other intents passes variable values (tint or spin in the sample) to the web app. The custom logic for the web app uses these values to update elements (animations, color, etc):

...
app.intent('start', (conv) => {
  conv.ask(`Ok, I'm spinning. What else?`);
  conv.ask(new HtmlResponse({
    data: {
      spin: true,
    },
  }));
});
...

Guidelines and restrictions

Keep the following guidelines and restrictions for HtmlResponse in mind when building your fulfillment:

  • Each intent in your fulfillment must include an HtmlResponse. If an intent does not include an HtmlResponse, your web app closes.
  • You only need to include your web app URL in the first intent you send to the user (this is normally the Welcome intent).
  • HtmlResponse must be 50kb or smaller in size.