Helpers

Helpers tell the Assistant to momentarily take over the conversation to obtain common data such as a user's full name, a date and time, or a delivery address. When you request a helper, the Assistant presents a standard, consistent UI to users to obtain this information, so you don't have to design your own.

Usage overview

The general process for using a helper with Dialogflow and Actions SDK is described below for Dialogflow and the Actions SDK. See the specific helper sections for more information about each helper.

Dialogflow

Node.js
  1. Call conv.ask() with the appropriate helper object. When you call a helper function, the client library sends a response to the Assistant that contains the corresponding helper intent. Based on the intent, the Assistant knows to carry out the dialog for the corresponding helper.
  2. Declare a Dialogflow intent that specifies an event that corresponds to one of the helper intents. See the helper intents section for a list of supported events. This intent doesn't need to have any User says phrases, because it's always triggered when the event is fired (when the Assistant is done carrying out the helper).
  3. When the Assistant returns the result of the helper in the subsequent request to your fulfillment, the corresponding Dialogflow intent is triggered, and you handle the intent normally.
JSON
  1. Specify the helper's intent in the possibleIntents object when responding to the Assistant. When the Assistant receives the response, it knows that it should carry out the dialog for the helper. See helper intents for information on what intents you can request to be fulfilled.
  2. Declare a Dialogflow intent that specifies an event that corresponds to one of the helper intents. See the helper intents section for a list of supported events. This intent doesn't need to have any User says phrases, because it's always triggered when the event is fired.
  3. When the Assistant returns the result of the helper in the subsequent request to your fulfillment, parse the request and the data you need.

Actions SDK

Node.js
  1. Call ask with the appropriate parameters. A helper function asks the Assistant to fulfill one of the intents described in helper intents. When you call a helper function, the client library sends a response to the Assistant that contains one of these intents. Based on the intent, the Assistant knows to carry out the dialog for the corresponding helper.
  2. When the Assistant returns the result of the helper in the subsequent request to your fulfillment, you receive the corresponding intent in the request. This lets you detect that a helper has returned a result. Use the corresponding getter function for the helper to obtain the data you need.
JSON
  1. Specify the helper's intent in the possibleIntents object when responding to the Assistant. When the Assistant receives the response, it knows that it should carry out the dialog for the helper. See helper intents for information on what intents you can request to be fulfilled.
  2. When the Assistant returns the result of the helper in the subsequent request to your fulfillment, parse the request and the data you need.

Helper intents

The following table describes the supported intents that you can request the Assistant to fulfill. If you're using Dialogflow, you also need to create a Dialogflow intent that specifies the corresponding event for the helper intent.

Intent name Dialogflow Event name Usage
actions.intent.PERMISSION actions_intent_PERMISSION Obtain the user's full name, coarse location, or precise location, or all 3.
actions.intent.OPTION actions_intent_OPTION Receive the selected item from a list or carousel UI.
actions.intent.DATETIME actions_intent_DATETIME Obtain a date and time input from the user.
actions.intent.SIGN_IN actions_intent_SIGN_IN Requests an account linking flow to link a user's account.
actions.intent.PLACE actions_intent_PLACE Obtain an address or saved location from the user.
actions.intent.DELIVERY_ADDRESS actions_intent_DELIVERY_ADDRESS Obtain a delivery address input from the user.
actions.intent.CONFIRMATION actions_intent_CONFIRMATION Obtain a confirmation from the user (for example, an answer to a yes or no question).
actions.intent.LINK actions_intent_LINK Requests a deep link flow into another platform.

The following sections describe the available helpers and the associated intent that you must request to use the helper.

User information

You can obtain the following user information with this helper:

  • Display name
  • Given name
  • Family name
  • Coarse device location (zip code and city)
  • Precise device location (coordinates and street address)

Calling the helper

You can call ask as shown below:

app.intent('ask_for_permission', (conv) => {
  conv.ask(new Permission({context, permission}));
});
app.intent('ask_for_permissions', (conv) => {
  conv.ask(new Permission({context, permissions}));
});

Note that the JSON below describes a webhook request using the Actions SDK.

Node.js
app.intent('ask_for_permissions_detailed', (conv) => {
  // Choose one or more supported permissions to request:
  // NAME, DEVICE_PRECISE_LOCATION, DEVICE_COARSE_LOCATION
  const options = {
    context: 'To address you by name and know your location',
    // Ask for more than one permission. User can authorize all or none.
    permissions: ['NAME', 'DEVICE_PRECISE_LOCATION'],
  };
  conv.ask(new Permission(options));
});

JSON
{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "initialPrompts": [
          {
            "textToSpeech": "PLACEHOLDER_FOR_PERMISSION"
          }
        ],
        "noInputPrompts": []
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.PERMISSION",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
            "optContext": "To deliver your order",
            "permissions": [
              "NAME",
              "DEVICE_PRECISE_LOCATION"
            ]
          }
        }
      ]
    }
  ]
}

Getting the results of the helper

The snippet below shows how to check if the user granted you the information and then access the data.

Node.js
app.intent('ask.for.permission.confirmation', (conv, params, confirmationGranted) => {
  const {name} = conv.user;
  if (confirmationGranted) {
    if (name) {
      conv.ask(`I'll send the driver you're way now ${name.display}.`);
    }
  }
});
JSON
{
  "user": {
    "userId": "user123",
    "profile": {
      "displayName": "Jane Smith",
      "givenName": "Jane",
      "familyName": "Smith"
    }
  },
  "conversation": {
    "conversationId": "1494884577894",
    "type": "ACTIVE",
    "conversationToken": "{\"state\":null,\"data\":{}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.PERMISSION",
      "rawInputs": [
        {
          "inputType": "KEYBOARD",
          "query": "yes"
        }
      ],
      "arguments": [
        {
          "name": "PERMISSION",
          "rawText": "yes",
          "textValue": "true"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      }
    ]
  },
  "device": {
    "location": {
      "coordinates": {
        "latitude": 37.422366,
        "longitude": -122.084406
      },
      "formattedAddress": "1600 Amphitheatre Parkway, Mountain View, CA 94043, United States",
      "zipCode": "94043",
      "city": "Mountain View"
    },
    "locale": "en-US"
  },
  "isInSandbox": false
}

Once you obtain the user's information, we recommend that you persist this information, so you don't have to ask again. You can use UserStorage to store user information across conversations. Check out our Name Psychic sample to see UserStorage in action.

You can display a list or carousel UI and obtain the selected item from the user with the actions.intent.OPTION intent.

Node.js
app.intent('ask_with_list', (conv) => {
  conv.ask('This is a simple response for a list.');
  conv.ask(new Suggestions([
    'Basic Card',
    'Browse Carousel',
    'Carousel',
    'List',
    'Media',
    'Suggestions',
  ]));
  // Create a list
  conv.ask(new List({
    title: 'Things to learn about',
    items: {
      // Add the first item to the list
      'MATH_AND_PRIME': {
        synonyms: [
          'math',
          'math and prime',
          'prime numbers',
          'prime',
        ],
        title: 'Title of the First List Item',
        description: '42 is an abundant number',
        image: new Image({
          url: 'https://example.com/math_and_prime.jpg',
          alt: 'Math & prime numbers',
        }),
      },
      // Add the second item to the list
      'EGYPT': {
        synonyms: [
          'religion',
          'egypt',
          'ancient egyptian',
      ],
        title: 'Ancient Egyptian religion',
        description: '42 gods ruled on the fate of the dead in the afterworld',
        image: new Image({
          url: 'http://example.com/egypt',
          alt: 'Egypt',
        }),
      },
      // Add the last item to the list
      'RECIPES': {
        synonyms: [
          'recipes',
          'recipe',
          '42 recipes',
        ],
        title: '42 recipes in 42 ingredients',
        description: 'A beautifully simple recipe',
        image: new Image({
          url: 'http://example.com/recipe',
          alt: 'Recipe',
        }),
      },
    },
  }));
});
JSON
{
    "conversationToken": "{\"state\":null,\"data\":{}}",
    "expectUserResponse": true,
    "expectedInputs": [
        {
            "inputPrompt": {
                "richInitialPrompt": {
                    "items": [
                        {
                            "simpleResponse": {
                                "textToSpeech": "Alright! Here are a few things you can learn. Which sounds interesting?"
                            }
                        }
                    ],
                    "suggestions": [
                        {
                            "title": "Basic Card"
                        },
                        {
                            "title": "List"
                        },
                        {
                            "title": "Carousel"
                        },
                        {
                            "title": "Suggestions"
                        }
                    ]
                }
            },
            "possibleIntents": [
                {
                    "intent": "actions.intent.OPTION",
                    "inputValueData": {
                        "@type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
                        "listSelect": {
                            "title": "Things to learn about",
                            "items": [
                                {
                                    "optionInfo": {
                                        "key": "MATH_AND_PRIME",
                                        "synonyms": [
                                            "math",
                                            "math and prime",
                                            "prime numbers",
                                            "prime"
                                        ]
                                    },
                                    "title": "Math & prime numbers",
                                    "description": "42 is an abundant number because the sum of its proper divisors 54 is greater…",
                                    "image": {
                                        "url": "http://example.com/math_and_prime.jpg",
                                        "accessibilityText": "Math & prime numbers"
                                    }
                                },
                                {
                                    "optionInfo": {
                                        "key": "EGYPT",
                                        "synonyms": [
                                            "religion",
                                            "egpyt",
                                            "ancient egyptian"
                                        ]
                                    },
                                    "title": "Ancient Egyptian religion",
                                    "description": "42 gods who ruled on the fate of the dead in the afterworld. Throughout the under…",
                                    "image": {
                                        "url": "http://example.com/egypt",
                                        "accessibilityText": "Egypt"
                                    }
                                },
                                {
                                    "optionInfo": {
                                        "key": "RECIPES",
                                        "synonyms": [
                                            "recipes",
                                            "recipe",
                                            "42 recipes"
                                        ]
                                    },
                                    "title": "42 recipes with 42 ingredients",
                                    "description": "Here's a beautifully simple recipe that's full of flavor! All you need is some ginger and…",
                                    "image": {
                                        "url": "http://example.com/recipe",
                                        "accessibilityText": "Recipe"
                                    }
                                }
                            ]
                        }
                    }
                }
            ]
        }
    ]
}

Getting the results of the helper

When users select an item, the selected item value is passed to you as an argument. The snippets below show how to check which item the user selected.

app.intent('ask_with_list_confirmation', (conv, params, option) => {
  // Get the user's selection
  // Compare the user's selections to each of the item's keys
  if (!option) {
    conv.ask('You did not select any item from the list or carousel');
  } else if (option === 'MATH_AND_PRIME') {
    conv.ask('42 is an abundant number because the sum of its...');
  } else if (option === 'EGYPT') {
    conv.ask('42 gods who ruled on the fate of the dead in the ');
  } else if (option === 'RECIPES') {
    conv.ask(`Here's a beautiful simple recipe that's full `);
  } else {
    conv.ask('You selected an unknown item from the list, or carousel');
  }
});

Date and Time

You can obtain a date and time from users by requesting fulfillment of the actions.intent.DATETIME intent.

Calling the helper

You can call ask as shown below:

app.intent('ask_for_datetime', (conv) => {
  conv.ask(new DateTime(options));
});

You can specify custom prompts when asking the user for a date and time using the options object when creating the DateTime permission.

Note that the JSON below describes a webhook request using the Actions SDK.

Node.js
app.intent('ask_for_datetime_detail', (conv) => {
  const options = {
    prompts: {
      initial: 'When would you like to schedule the appoinment?',
      date: 'What day was that?',
      time: 'What time?',
    },
  };
  conv.ask(new DateTime(options));
});
JSON
{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "initialPrompts": [
          {
            "textToSpeech": "PLACEHOLDER_FOR_DATETIME"
          }
        ],
        "noInputPrompts": []
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.DATETIME",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.DateTimeValueSpec",
            "dialogSpec": {
              "requestDatetimeText": "When do you want to come in?",
              "requestDateText": "What is the best date to schedule your appointment?",
              "requestTimeText": "What time of day works best for you?"
            }
          }
        }
      ]
    }
  ]
}

Getting the results of the helper

The snippet below shows how to check whether the user has granted access and how to access the data.

Node.js
app.intent('ask_for_datetime_confirmation', (conv, params, confirmatinGranted) => {
  if (confirmationGranted) {
    conv.ask('Alright, date set.');
  } else {
    conv.ask(`I'm having a hard time finding an appointment`);
  }
});
JSON
{
  "user": {
    "userId": "user123"
  },
  "conversation": {
    "conversationId": "1494884466160",
    "type": "ACTIVE",
    "conversationToken": "{\"state\":null,\"data\":{}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.DATETIME",
      "rawInputs": [
        {
          "inputType": "VOICE",
          "query": "tuesday at 9"
        }
      ],
      "arguments": [
        {
          "name": "DATETIME",
          "datetimeValue": {
            "date": {
              "year": 2017,
              "month": 5,
              "day": 16
            },
            "time": {
              "hours": 9
            }
          }
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      }
    ]
  },
  "device": {
    "locale": "en-US"
  },
  "isInSandbox": false
}

Account Sign-in

You can have users sign-in to their accounts that are associated with your service by requesting fulfillment of the actions.intent.SIGN_IN intent.

Calling the helper

You can call ask as shown below:

app.intent('ask_for_sign_in', (conv) => {
  conv.ask(new SignIn());
});

Note that the JSON below describes a webhook request using the Actions SDK.

Node.js
app.intent('ask_for_sign_in_detail', (conv) => {
  conv.ask(new SignIn());
});

JSON
{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "initialPrompts": [
          {
            "textToSpeech": "PLACEHOLDER_FOR_SIGN_IN"
          }
        ],
        "noInputPrompts": []
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.SIGN_IN",
          "inputValueData": {}
        }
      ]
    }
  ]
}

Getting the results of the helper

The snippet below shows how to check whether the user has granted access and how to access the data.

Node.js
app.intent('ask_for_sign_in_confirmation', (conv, params, signin) => {
  if (signin.status !== 'OK') {
    return conv.ask('You need to sign in before using the app.');
  }
  // const access = conv.user.access.token;
  // possibly do something with access token
  return conv.ask('Great! Thanks for signing in.');
});
JSON
{
  "isInSandbox'": false,
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      }
    ]
  },
  "inputs": [
    {
      "rawInputs": [
        {
          "query": "i think so",
          "inputType": "VOICE"
        }
      ],
      "arguments": [
        {
          "name": "SIGN_IN",
          'extension': {
            "@type": "type.googleapis.com/google.actions.v2.SignInValue",
            "status": "OK"
          }
        }
      ],
      "intent': "actions.intent.SIGN_IN"
    }
  ],
  "user": {
    "userId": "user123"
  },
  "device": {
    "locale": "en-US"
  },
  "conversation": {
    "conversationId": "1494606917128",
    "type": "ACTIVE",
    "conversationToken": "[\"_actions_on_google_\"]"
  }
};

Place and Location

You can obtain a location from users by requesting fulfillment of the actions.intent.PLACE intent. This helper is used to prompt the user for addresses and other locations, including any home/work/contact locations that they've saved with Google.

Saved locations will only return the address, not the associated mapping (e.g. "123 Main St" as opposed to "HOME = 123 Main St").

Calling the helper

You can call ask as shown below:

app.intent('ask_for_place', (conv) => {
  conv.ask(new Place(options));
});

Note that the JSON below describes a webhook request using the Actions SDK.

Node.js
app.intent('ask_for_place_detail', (conv) => {
  const options = {
    context: 'To find a place to pick you up',
    prompt: 'Where would you like to be picked up?',
  };
  conv.ask(new Place(options));
});
JSON
{
  "intent": "actions.intent.PLACE",
    "inputValueData": {
    "@type": "type.googleapis.com/google.actions.v2.PlaceValueSpec",
    "dialog_spec": {
      "extension": {
        "@type": "type.googleapis.com/google.actions.v2.PlaceValueSpec.PlaceDialogSpec",
        "requestPrompt": "Where do you want to have lunch?",
        "permissionContext": "To find lunch locations"
      }
    }
  }
}

Getting the results of the helper

The snippet below shows how to check whether the user has granted access and how to access the data.

Node.js
app.intent('ask_for_place_confirmation', (conv, params, place, status) => {
  if (!place) return conv.ask(`Sorry, I couldn't get a location from you`);
  // the place also carries formattedAddress, and coordinates fields
  const {name} = place;
  if (place.name) conv.ask(`Alright! I'll send the car to ${name}`);
});
JSON
// Successful response format
"inputs": [
  {
    "intent":"actions.intent.PLACE",
    "arguments": [
      {
        "name":"PLACE",
        "placeValue": {
          "coordinates":{
            "latitude": 37.3911801,
            "longitude": -122.0810139
          },
          "name": "Cascal"
          "formattedAddress": "Cascal, 400 Castro Street, Mountain View, CA 94041, United States",
          // Note that the client library uses address instead of formattedAddress as
          // shown here
          "placeId": "ChIJ03QfnzO3j4ARC0p7TSYoCpA"
        }
      }
    ]
  }
]

// Error response format
"inputs": [
  {
    "intent":"actions.intent.PLACE",
    "arguments": [
      {
        "name":"PLACE",
        "status": {
          "code": 7, // PERMISSION_DENIED
          "message": "User denied location permission"
        }
      }
    ]
  }
]

Confirmation

You can ask a generic confirmation from the user (yes/no question) and get the resulting answer. The grammar for "yes" and "no" naturally expands to things like "Yea" or "Nope", making it usable in many situations.

Request the helper

You can call ask as shown below:

app.intent('ask_for_confirmation', (conv) => {
  conv.ask(new Confirmation(prompt));
});

You can specify a custom prompt when asking the user for a confirmation.

Note that the JSON below describes a webhook request using the Actions SDK.

Node.js
app.intent('ask_for_confirmation_detail', (conv) => {
  conv.ask(new Confirmation('Can you confirm?'));
});

JSON
{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "initialPrompts": [
          {
            "textToSpeech": "PLACEHOLDER_FOR_CONFIRMATION"
          }
        ],
        "noInputPrompts": []
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.CONFIRMATION",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.ConfirmationValueSpec",
            "dialogSpec": {
              "requestConfirmationText": "Will you marry me?"
            }
          }
        }
      ]
    }
  ]
}

Getting the results of the helper

After the user responds to the helper, you receive a request to your fulfillment and can check whether the user confirmed or not.

Node.js
app.intent('ask_for_confirmation_confirmation', (conv, params, confirmationGranted) => {
  return conv.ask(confirmationGranted ? 'Wonderful' : 'Maybe next time');
});
JSON
{
  "user": {
    "userId": "user123"
  },
  "conversation": {
    "conversationId": "1494884269122",
    "type": "ACTIVE",
    "conversationToken": "{\"state\":null,\"data\":{}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.CONFIRMATION",
      "rawInputs": [
        {
          "inputType": "VOICE",
          "query": "yes"
        }
      ],
      "arguments": [
        {
          "name": "CONFIRMATION",
          "boolValue": true
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      }
    ]
  },
  "device": {
    "locale": "en-US"
  },
  "isInSandbox": false
}

You can ask the user to continue an interaction via your Android app. This helper allows you to prompt the user as part of the conversation. You'll first need to associate your Android app with your Actions Console project via the Brand Verification page.

Request the helper

You can call ask as shown below:

app.intent('ask_to_deep_link', (conv) => {
  conv.ask(new DeepLink(options));
});

Note that the JSON below describes a webhook request using the Actions SDK.

Node.js
app.intent('ask_to_deep_link_detail', (conv) => {
  const options = {
    destination: 'Google',
    url: 'example://gizmos',
    package: 'com.example.gizmos',
    reason: 'handle this for you',
  };
  conv.ask('Great! looks like maybe we can do that in the app.');
  conv.ask(new DeepLink(options));
});
JSON
{
  "conversationToken": "{\"state\":null,\"data\":{}}",
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "inputPrompt": {
        "initialPrompts": [
          {
            "textToSpeech": "Great choice!"
          }
        ],
        "noInputPrompts": []
      },
      "possibleIntents": [
        {
          "intent": "actions.intent.LINK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.LinkValueSpec",
            "openUrlAction": {
              "url": "https://example.com/deeplink1",
              "androidApp": { "packageName": "com.example.app" }
            },
            "dialogSpec": {
              "requestLinkReason": "watch that video"
            }
          }
        }
      ]
    }
  ]
}

Getting the results of the helper

If the user accepts the link, the dialog with your Action will end and you will not receive further requests. If they reject the link, you will receive another request with the intent actions.intent.LINK and a status argument:

Node.js
app.intent('ask_to_deep_link_confirmation', (conv, params, response) => {
  conv.ask('Okay maybe we can take care of that another time.');
});
JSON
{
  "user": {
    "userId": "user123"
  },
  "conversation": {
    "conversationId": "1494884269122",
    "type": "ACTIVE",
    "conversationToken": "{\"state\":null,\"data\":{}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.LINK",
      "arguments": [
        {
          "name": "LINK",
          "status": {
            "code": 9
          }
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      }
    ]
  },
  "device": {
    "locale": "en-US"
  },
  "isInSandbox": false
}