9

I would like my Actions on Google agent to store and retrieve certain pieces of information across invocations - like a cookie. How do I do this?

Prisoner
  • 49,922
  • 7
  • 53
  • 105
Lord Loh.
  • 2,437
  • 7
  • 39
  • 64

5 Answers5

19

You have a lot of options on how you want to do this, depending on exactly what you're trying to do. It isn't exactly like a web cookie, although there are similarities.

If you want the equivalent of a session cookie, information that is retained during a single conversation, then your options are

  • Using the Session ID provided as part of the information sent to you on each invocation and tracking this in your fulfillment.
  • Storing information you want retained using a Dialogflow context
  • If you are using the actions-on-google JavaScript library, storing this in the app.data object created for you.

If you want the equivalent of a long-lasting cookie to retain information between conversations then your options are

  • Using the anonymous User ID provided as part of the information sent to you on each invocation and tracking this in your fulfillment.
  • If you are using the actions-on-google javascript library, storing this in the app.userStorage object created for you.
  • Storing it as part of the string in the JSON response under data.google.userStorage.

Some more information about each of these

Session ID

A different Session ID is created for each conversation you have. You can get this Session ID by examining the JSON sent to your webhook in the sessionId parameter.

You can then look this up in a data store of some sort that you manage.

Dialogflow context

Contexts are powerful tools that are available with Dialogflow. You return a context as part of your fulfillment webhook and indicate the name of the context, its lifetime (how many more rounds of the conversation it will be passed back to your webhook), and any parameters associated with the context (string key/value pairs).

Contexts are especially useful in helping determine what intents may be called. You can indicate what contexts must be active for an Intent to be recognized by Dialogflow.

If you're using the actions-on-google node.js library, you can set a context using something like this:

var contextParameters = {
  foo: "Something foothy",
  bar: "Your local bar."
};
app.setContext( "remember_this", 5, contextParameters );

You need to do this before you call app.ask() or app.tell().

Or you can do the equivalent in the JSON as part of the contextOut block of the response

"contextOut": [
  {
    "name": "remember_this",
    "lifespan": 5,
    "parameters": {
      "foo": "Something foothy",
      "bar": "Your local bar."
    }
  }
]

The next time your webhook is called, you can fetch this context either by looking at the result.contexts array or by using the app.getContext() or app.getContextArgument() methods in the library.

Using app.data

If you're using the library, Google has done some of the work for you. The app.data object is created for you. Any values you set in the object are available for the lifetime of the session - you just read them in later calls to your webhook.

(Under the covers, Google uses a context for this, so there is no magic. The two work together and you're free to do both.)

Anonymous UserID

When a user first uses your action, a user ID is generated. This ID doesn't give you access to any specific information about them, and isn't used for any other action, but every time you see it, you can be assured that it was the same user that used it on a previous occurrence. Just like a cookie, however, the user can reset it and a new ID will be generated for them for your action.

You get this from the JSON at originalRequest.user.userId or by using app.getUser().userId. Once you have it, you'd use a data store of some sort to store and retrieve information about this user.

Using app.userStorage

Similar to app.data, there is also an app.userStorage object that is created for you for each user. Any changes you make to this object are saved in between conversations you have with this user.

Unlike app.data, however, this doesn't get stored in a context. It has its own storage method. Which leads to...

Storing it in JSON

If you're not using the actions-on-google library, you still have access to userStorage through the response and request JSON directly. You need to store this as a string, but if you need to store a more complex object, a common method is to stringify it as JSON.

You'll store this value under data.google.userStorage in the response and can retrieve it under originalRequest.data.user.userStorage in the request your webhook receives.

Prisoner
  • 49,922
  • 7
  • 53
  • 105
  • I built an agent to tell me my Robinhood Trading Account portfolio value, cash and stock values. Each time I ask one of these, my back end webhook (a CGI python script) is invoked and it queries the upstream robinhood server. I would like to avoid that by caching all the information for a short while. Also, my username and password are currently hardcoded in the CGI python :-( I cannot figure out how to get and save this with the user's account data. Thank you for the answer :-) – Lord Loh. Nov 28 '17 at 18:39
  • It isn't clear if you're asking a followup question, giving background, or what exactly you need. If this answers your question - accepting and/or upvoting it is appreciated. If it does not, and you need additional information, please update your original question to clarify what you've tried, what isn't working about what you've tried, and providing as much additional info as possible that will help us help you. – Prisoner Nov 28 '17 at 19:50
  • I am using `WebhookClient`. How can I use `app.data`? – Mehmed Apr 08 '18 at 07:36
  • @Mehmed - You should probably ask that as a new StackOverflow question, providing an example of what you're doing now and what isn't working. – Prisoner Apr 08 '18 at 11:56
1

You can save the information in Context with a key value parameter.

SAVING VALUES IN CONTEXT :

agent.set.Context({
  name:'context-name',
  lifespan: 5,
  parameters:{
    'parameter-name':'parameter-value'
    }
});

GETTING VALUES FROM CONTEXT

 agent.getContext('context-name');

For more Details : https://dialogflow.com/docs/contexts/contexts-fulfillment

Ajay Venugopal
  • 1,544
  • 1
  • 17
  • 30
  • Can you post here how to access the parameter in the get part? Because I have done exactly this and when I try to fetch the parameter value it does not work. I tried: agent.setContext({ name: '70-confirmation1', lifespan: 5, parameters: { originalQuestion: agent.query }}); and then in the next intent: agent.getContext('70-confirmation1'); agent.add(`Your initial question was: ${agent.parameters.originalQuestion} `); – JS_Diver Feb 18 '20 at 15:10
  • 1
    Here you are not fetching the correct parameters. First you need to getcontext and then get parameters. Here you are trying to fetch original question as from a global parameters. That's wont work as expected. Try something like agent.getcontect(70-conf1).originalquestion. try like this and let me know – Ajay Venugopal Feb 23 '20 at 18:17
0

You could also use a Google Cloud database like BigQuery or Firestore

0

Sounds like you may want to checkout out Account Linking: https://developers.google.com/actions/identity/account-linking. With account linking you can collect end-user information which you exchange with Google by providing a unique key. This unique key becomes part of every request you receive from Google, so when you get that unique key you lookup the information you collected from the end-user. In your case, you would store credentials or whatever key is required to access the end-user information. After the initial linking, any new data you obtain could be stored along with the original information collected, based on the unique key obtained during account linking.

NinePlanFailed
  • 385
  • 4
  • 11
0

For this purpose, i just did a node module just for that, in external json file from api call, i need to store and add additional informations to retrieve later. I thing that you can do a lot with this module, Store object, array, json, value, Navigation history?, back to previous page. It work like localStorage or Cookies. There's no limit, you can create multiple storage by name (key) an value. It's new and i'm testing it for bugs right now on my own project.

Test on Runkit

On npm

vStorage = require('virtual-storage');
vStorage.set('name', '{title:'Title 1', description:'Descriptions 1'}')
let getStorage_name = vStorage.get('name');
console.log(getStorage_name.title);
vStorage.get('name')
Gino
  • 1,834
  • 2
  • 19
  • 20