Explore in Dialogflow
Click Continue to import our Save data sample in Dialogflow. Then, follow the steps below to deploy and test the sample:
- Enter an agent name and create a new Dialogflow agent for the sample.
- After the agent is done importing, click Go to agent.
- From the main navigation menu, go to Fulfillment.
- Enable the Inline Editor, then click Deploy. The editor contains the sample code.
- From the main navigation menu, go to Integrations, then click Google Assistant.
- In the modal window that appears, enable Auto-preview changes and click Test to open the Actions simulator.
- In the simulator, enter
Talk to my test app
to test the sample!
Part of providing an excellent user experience is often being able to save data between turns of a conversation or across multiple conversations with a user. This is helpful if you're providing helpful reprompts in a single conversation, saving game scores across sessions, or remembering small pieces of information for a user.
The requirements vary slightly based on whether you need to save data within a
conversation or across conversations. To save data in a conversation, you can
use the conversationToken
field of your AppResponse
object.
To save data across conversations, take the following steps instead:
- Determine whether the user is verified or a guest.
- Store or access user data using the
userStorage
field of yourAppResponse
object.
Saving data between turns of a conversation
The conversationToken
field is a string that contains an opaque token that
is recirculated to the Action every conversation turn. For example, if you set
the value to "count=1"
in your AppResponse
for the first turn of the
conversation, the AppRequest
received by your Action for the second turn
of the conversation contains "count=1"
in its conversationToken
.
The token is always initialized to an empty string at the beginning of a
conversation. If you use the
Actions on Google Node.js client library, you can
interface with the conversation token as a JSON object using conv.data
, where
conv
is your instance of Conversation
.
The following sample shows how to save a counter in the conversationToken
field of your AppResponse
:
Node.js
conv.data.firstNum = firstNum; conv.ask(`Got it, the first number is ${firstNum}.`); conv.ask(`What's the second number?`);
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.getConversationData().put("firstNum", firstNum); responseBuilder.add("Got it, the first number is " + firstNum + "."); responseBuilder.add("What's the second number?"); return responseBuilder.build();
JSON
Note that the JSON below describes a webhook response which uses
outputContexts
instead of conversationToken
.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Got it, the first number is 23." } }, { "simpleResponse": { "textToSpeech": "What's the second number?" } } ] } } }, "outputContexts": [ { "name": "projects/save-data-df-js/agent/sessions/ABwppHGfFkWJdHKPpBEYiGkhdoakWmYj_2sZa4o8pbGG9nj4q5_GfDTtNEXOY34mLX8G4o_d7oZdUW9bnBZC/contexts/_actions_on_google", "lifespanCount": 99, "parameters": { "data": "{\"firstNum\":23}" } } ] }
JSON
Note that the JSON below describes a webhook response.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Got it, the first number is 23." } }, { "simpleResponse": { "textToSpeech": "What's the second number?" } } ] } } } ], "conversationToken": "{\"data\":{\"firstNum\":23}}" }
See our Provide helpful reprompts and fail gracefully best practice guide for a practical usage example.
Saving data across conversations
The userStorage
field of your AppResponse
object is a string that
contains an opaque token supplied by the Action that is saved across
conversations for a particular user. For example, a game can save the highest
score of a user in userStorage
and use its value in the welcome message each
time the user starts a new conversation.
Determining and handling user verification status
A user's verification status can have a value of GUEST
or VERIFIED
. At the
start of each conversation, Actions on Google sets the user's verification
status based on a variety of indicators when the conversation starts. As one
example, a user logged in to the Google Assistant on their mobile device has a
verification status of VERIFIED
.
The following are possible reasons for a user to have a verification status of
GUEST
:
- The user has personal results turned off.
- The user disabled their Web & App Activity. Keep in mind that some users may have this setting disabled at the domain level.
- If a device has Voice Match enabled, and the match fails or the user invokes the Assistant without using their voice (such as a long press on a Google Home).
- The user isn't signed in.
Always check the user's verification status before storing data with
userStorage
or starting an account linking flow to prevent guest users from
interacting with a feature that will fail for them.
If you use the Actions On Google Client Library for Node.js,
you can interface with the user storage as a JSON object using
conv.user.storage
, where conv
is your instance of Conversation
. The
following sample shows how to save a counter in the userStorage
field of your
AppResponse
:
Node.js
app.intent('Save Sum', (conv) => { if (conv.user.verification === 'VERIFIED') { conv.user.storage.sum = conv.data.sum; conv.close(`Alright, I'll store that for next time. See you then.`); } else { conv.close(`I can't save that right now, but we can add ` + `new numbers next time!`); } });
Java
@ForIntent("Save Sum") public ActionResponse saveSum(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); Integer sum = ((Double) request.getConversationData().get("sum")).intValue(); String verificationStatus = request.getUser().getUserVerificationStatus(); if (verificationStatus.equals("VERIFIED")) { responseBuilder.getUserStorage().put("sum", sum); responseBuilder.add("Alright, I'll store that for next time. See you then."); } else { responseBuilder.add("I can't save that right now, but we can add new numbers next time!"); } responseBuilder.endConversation(); return responseBuilder.build(); }
Node.js
if (conv.user.verification === 'VERIFIED') { conv.user.storage.sum = conv.data.sum; conv.close(`Alright, I'll store that for next time. See you then.`); } else { conv.close(`I can't save that right now, but we can add ` + `new numbers next time!`); }
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); Integer sum = ((Double) request.getConversationData().get("sum")).intValue(); String verificationStatus = request.getUser().getUserVerificationStatus(); if (verificationStatus.equals("VERIFIED")) { responseBuilder.getUserStorage().put("sum", sum); responseBuilder.add("Alright, I'll store that for next time. See you then."); } else { responseBuilder.add("I can't save that right now, but we can add new numbers next time!"); } responseBuilder.endConversation(); return responseBuilder.build();
JSON
Note that the JSON below describes a webhook response.
{ "payload": { "google": { "expectUserResponse": false, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Alright, I'll store that for next time. See you then." } } ] }, "userStorage": "{\"data\":{\"sum\":68}}" } } }
JSON
Note that the JSON below describes a webhook response.
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Alright, I'll store that for next time. See you then." } } ] } }, "conversationToken": "{\"data\":{\"firstNum\":23,\"sum\":68}}", "userStorage": "{\"data\":{\"sum\":68}}" }
See our Personalize the conversation with user preferences best practice guide for a practical usage example.
Legal note: Obtaining consent prior to accessing userStorage
.
Some countries have regulations that require developers to obtain consent from
the user before they can access, or save certain information (like personal
information) in the userStorage
. If you operate in one of these
countries and you want to access, or save such information in
userStorage
, you must use the
Confirmation helper to ask
consent to the user and obtain the consent before you can start storing such
information in userStorage
.
User storage expiration
When the Assistant can match an identity to the user, the contents of
userStorage
never expires, and only the user or the Action itself can clear it.
When the Assistant can't match an identity to the user, the content of
userStorage
is cleared at the end of the conversation. Here are some examples
cases where the Assistant can't match an identity to the user:
- Voice match is set up and there is no match.
- The user disabled personal data.
Clear content of the userStorage field
You can clear the content of the userStorage
field of your Action by
setting the resetUserStorage
field of your AppResponse
to true. If
you set the value of userStorage
to an empty string, the value of
userStorage
remains unaltered in the next turn of conversation. This lets you
avoid sending back the whole userStorage
in turns where its content didn't
change.
If you are using the Actions On Google Client Library for Node.js,
you can just set the value of conv.user.storage
to {}
(empty object).
Node.js
app.intent('Forget Number', (conv) => { conv.user.storage = {}; conv.ask(`Alright, I forgot your last result.`); conv.ask(`Let's add two new numbers. What is the first number?`); });
Java
@ForIntent("Forget Number") public ActionResponse forgetNumber(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.getUserStorage().clear(); responseBuilder.add("Alright, I forgot your last result."); responseBuilder.add("Let's add two new numbers. What is the first number?"); return responseBuilder.build(); }
Node.js
conv.user.storage = {}; conv.ask(`Alright, I forgot your last result.`); conv.ask(`Let's add two new numbers. What is the first number?`);
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.getUserStorage().clear(); responseBuilder.add("Alright, I forgot your last result."); responseBuilder.add("Let's add two new numbers. What is the first number?"); return responseBuilder.build();
JSON
Note that the JSON below describes a webhook response.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Alright, I forgot your last result." } }, { "simpleResponse": { "textToSpeech": "Let's add two new numbers. What is the first number?" } } ] }, "userStorage": "{\"data\":{}}" } } }
JSON
Note that the JSON below describes a webhook response.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Alright, I forgot your last result." } }, { "simpleResponse": { "textToSpeech": "Let's add two new numbers. What is the first number?" } } ] } } } ], "userStorage": "{\"data\":{}}" }
As a user, you can view the content of the userStorage
field in an Action you
invoked. You can also remove your stored user data from that specific Action
by stopping the service from remembering you.
- Open the Assistant app on your phone.
- Tap the drawer icon.
- In the Explore tab, find the Action you want to view or clear the user storage for and tap on it to open the details page.
- Scroll to the bottom of the page.
- To view the content of the
userStorage
field, tap [View stored data]. - To remove the stored user data, tap Stop $action from remembering me.
- To view the content of the