<br />

> [!NOTE]
> **Try the snippets:** Import, deploy, and explore code snippets in context using a new
> Dialogflow agent.
> <button class="devsite-dialog-button" data-modal-dialog-id="one-click-modal-dialog">Explore in Dialogflow</button>

### Explore in Dialogflow

Click **Continue** to import our Save data sample in Dialogflow. Then, follow the
steps below to deploy and test the sample:

1. Enter an agent name and create a new Dialogflow agent for the sample.
2. After the agent is done importing, click **Go to agent**.
3. From the main navigation menu, go to **Fulfillment**.
4. Enable the **Inline Editor** , then click **Deploy**. The editor contains the sample code.
5. From the main navigation menu, go to **Integrations** , then click **Google
   Assistant**.
6. In the modal window that appears, enable **Auto-preview changes** and click **Test** to open the Actions simulator.
7. In the simulator, enter `Talk to my test app` to test the sample!
[Continue](https://console.dialogflow.com/api-client/#/oneclick?templateUrl=https:%2F%2Fstorage.googleapis.com%2Fdialogflow-oneclick%2Fone_click_artifacts%2Fsave-dataOneClick.zip) <button class="devsite-dialog-close">Cancel</button>

<br />

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`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt#FIELDS.conversation_token) field of your [`AppResponse`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt) object.

To save data across conversations, take the following steps instead:

1. Determine whether the user is verified or a guest.
2. Store or access user data using the [`userStorage`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt#FIELDS.user_storage) field of your [`AppResponse`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt) object.

> [!WARNING]
> **Warning:** Only verified users can store information across conversations in `userStorage`. If a user's verification status is `GUEST`, then account management with [account linking](https://developers.google.com/assistant/identity.md.txt) and accessing `userStorage` will both fail.

## Saving data between turns of a conversation

The [`conversationToken`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt#FIELDS.conversation_token) 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`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt) for the first turn of the
conversation, the [`AppRequest`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppRequest.md.txt) 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](https://github.com/actions-on-google/actions-on-google-nodejs), you can
interface with the conversation token as a JSON object using `conv.data`, where
`conv` is your instance of `Conversation`.

> [!NOTE]
> **Note:** The `Conversation.conversationToken` field is not supported by Dialogflow webhook requests. Instead, your fulfillment can use a Dialogflow context to persist data across the conversation lifespan.

The following sample shows how to save a counter in the `conversationToken`
field of your [`AppResponse`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt):

### Node.js

```javascript
conv.data.firstNum = firstNum;
conv.ask(`Got it, the first number is ${firstNum}.`);
conv.ask(`What's the second number?`);
```

### Java

```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](https://developers.google.com/assistant/df-asdk/dialogflow/tips.md.txt#provide_helpful_reprompts_and_fail_gracefully)
best practice guide for a practical usage example.

## Saving data across conversations

The [`userStorage`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt#FIELDS.user_storage) field of your [`AppResponse`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt) 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.

> [!CAUTION]
> **Caution:** You can only store or access data across conversations for verified users. Attempting to store or access user data using `userStorage` will fail for guest users.

### 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](https://support.google.com/googlehome/answer/7684543) turned off.
- The user disabled their [Web \& App Activity](https://support.google.com/googlenest/answer/7382500). 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](https://developers.google.com/assistant/identity.md.txt) 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](https://github.com/actions-on-google/actions-on-google-nodejs),
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`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt):

### Node.js

```javascript
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

```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

```javascript
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

```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](https://developers.google.com/assistant/df-asdk/dialogflow/tips.md.txt#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](https://developers.google.com/assistant/df-asdk/helpers.md.txt#confirmation) 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`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt#FIELDS.user_storage) field of your Action by
setting the [`resetUserStorage`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt#FIELDS.reset_user_storage) field of your [`AppResponse`](https://developers.google.com/assistant/df-asdk/reference/webhook/rest/Shared.Types/AppResponse.md.txt) 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](https://github.com/actions-on-google/actions-on-google-nodejs),
you can just set the value of `conv.user.storage` to `{}` (empty object).

### Node.js

```javascript
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

```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

```javascript
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

```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.

1. Open the Assistant app on your phone.
2. Tap the drawer icon. ![](https://developers.google.com/static/assistant/conversational/images/open-assistant-settings.png)

3. 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.
4. 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**.