Botframework-webchat: Send custom ChannelData

Created on 23 Mar 2017  Â·  18Comments  Â·  Source: microsoft/BotFramework-WebChat

I am new to this. I want to send custom ChannelData object from webchat to my bot. I can see that in current implementation web chat adds clientActivityId to ChannelData and before sending to directline.

Is there a way I can attach additional data to ChannelData field for every message which is sent?

Most helpful comment

I thought this through a bit more and realized that we don't need a new property to WebChat. This is a great example of client middleware. I just tested this code and it worked great:

var dl = new BotChat.DirectLine({secret});

BotChat.App({
    botConnection: {
    … dl,
    postActivity: activity => dl.postActivity({
        … activity,
        channelData: // your data goes here 
    })
    },
    // other Chat props
});

I'm going to go ahead and close this issue, but feel free to add any questions or comments.

P.S. The above object spread syntax may need to be adapted for older browsers by compiling with TypeScript or replacing with Object.assign

All 18 comments

Not without altering the code. Can you say a little more about what you're trying to accomplish?

Right now I was creating an dashboard for human agents (scenario was live human handover). I wanted to send some agent related information(couple of IDs) and thought to use ChannelData. Anyways I managed it by fetching it from server side and storing in his state.

But now if I think of it, in case of backchannel type integration, it would be quite useful if you could send additional data along with the message. For example, you could send GPS information or maybe send current state of my web app (when guiding the user to fill form). ChannelData seems to be the right place to do it if I am not mistaken.

The way I think about this is that channelData is for additional data that is related to that specific message, like the GPS location the user was at when the message was sent. The backchannel is for data independent of messages, e.g. a stream of GPS locations sent every minute.

The live human handover case you mention is probably more of a backchannel scenario, as you would likely want the hosting page to send information independent of any messages.

If you did want to modify channelData, there would need to be an extensibility hook in WebChat, which is otherwise a pretty closed system. Perhaps a callback passed to the props, e.g. { channelDataCallback: (activity: Activity) => any } which would allow the page to inspect a message on its way out and return channelData to be attached to that message. But I'm not yet convinced that this is a particularly likely scenario.

You are right. GPS was just an example I picked up. There are scenarios where you would like to send additional information along with the message. One example would be send the state of the app if you are guiding user in filling the form. It may even simply be which page URL or page section, if he is asking questions related to what he is viewing.

Currently there is no way I could add any information to the Activity sent and sending separate event containing these data and then correlating them with previously sent user message is unnecessary when we do have a property in the current Activity which goes un-utilized. I see no reason why not to allow sending additional information in ChannelData.

The callback mechanism is very much in line with what I was thinking.

@danmarshall @eanders-MS @GeekTrainer any opinions on my proposal?

I've seen a few requests come through looking for the ability to send various pieces of information behind the scenes. I like the solution at its face.

I'm playing around with an implementation of this. Now the callback is called addChannelData which I think we can all agree is better.

Next question: should it be async? I'm a tentative yes.

If so, Promise<any> or Observable<any>? The case for the former is that it would be easy to drop in any existing promise, e.g. fetch. The case for the latter is that the rest of WebChat uses Observables, and you can convert a Promise to an Observable using Observable.fromPromise()

I'm tentatively thinking both. Which is to say, Promise<any> | Observable<any>. Should be relatively straightforward to sniff out which it is and do the necessary conversion if a Promise.

Update: Maybe we could do any | Promise<any> | Observable<any> and thus support both blocking and async functions?

I thought this through a bit more and realized that we don't need a new property to WebChat. This is a great example of client middleware. I just tested this code and it worked great:

var dl = new BotChat.DirectLine({secret});

BotChat.App({
    botConnection: {
    … dl,
    postActivity: activity => dl.postActivity({
        … activity,
        channelData: // your data goes here 
    })
    },
    // other Chat props
});

I'm going to go ahead and close this issue, but feel free to add any questions or comments.

P.S. The above object spread syntax may need to be adapted for older browsers by compiling with TypeScript or replacing with Object.assign

@billba I just came across this and wonder if you could complete the example without the "...."? What would the code have to look like if I wanted to intercept all postActivity calls and add some channel data like an object with two keys and value?

@Krumelur That is exactly what this code does. channelData can be any JSON object. The ... is not omitting something - that is actual modern JavaScript syntax.

Oh. Says a lot about how well I know Javascript! Tried it and it does not fail. But it never hits the line postActivity: activity => dl.postActivity({ when sending a message in the web chat. All I get in my bot is the default channel data {{ "clientActivityId": "1503000315680.543842980207524.2" }}

Not sure what to tell you. Worked when I tried it. Suggest you add some debugging code, i.e.

postActivity: activity => {
    console.log("posting");
    return dl.postActivity(activity);
}

Awesome, got it to work. Thanks!

BotChat.App({
            dl:
            {
                ...dl,
                postActivity: activity => {
                    // Add some custom data
                    activity.channelData.MyKey = "MyValue";
                    return dl.postActivity(activity)
                }
            },
            bot: bot,
            user: user,
            resize: 'detect',
        }, document.getElementById('bot'));

Edge does not support spread syntax. This is an alternative method:

BotChat.App({
  botConnection: Object.assign({}, dl, {
     postActivity: activity => {
     var newActivity = Object.assign({}, activity, { channelData: { "MyKey": "MyValue" } });
     return dl.postActivity(newActivity);
    }
  }),
  bot: bot,
  user: user,
  resize: 'detect',
}, document.getElementById('bot'));

Thanks @mgbennet for help translating ... to Object.assign()

even with the proposed workaround, when my server receives a _ConversationUpdate_, the ChannelData property is always null.

@JobaDiniz You are correct. Channel Data is not sent with ConversationUpdate. The workaround is to not rely on ConversationUpdate. This blog post goes into more detail: https://blog.botframework.com/2018/07/12/how-to-properly-send-a-greeting-message-and-common-issues-from-customers/

@EricDahlvang How can bot (using NodeJS SDK v3) can send additional data to webchat?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Stardox picture Stardox  Â·  3Comments

vikramdadwal picture vikramdadwal  Â·  3Comments

corinagum picture corinagum  Â·  3Comments

GewoonMaarten picture GewoonMaarten  Â·  3Comments

naveen-vijay picture naveen-vijay  Â·  4Comments