A newer feature of the facebook send api is to have referral parameters that can help qualify a user when they arrive at the bot. Currently the payload is either (1) attached to the get started button, or (2) sent as a messaging_referral event that the webhook must subscribe to.
I can receive the payload in case (1) [I'm using Node.js] in the session.message.sourcEvent. In case (2), the payload gets received if I am waiting for a message (as in a prompt). However, I have check for it manually in every waterfall step of my bot. It would be much more civil is there was a way to directly subscribe to the messaging_referral and to make an action using the referral.
https://developers.facebook.com/docs/messenger-platform/referral-params
Would the send/session middleware help you intercept all messages?
Thanks for the tags @willportnoy. I think so -- is there a link to something I am missing?
@willportnoy 's comment lead me to try using bot.use. My remaining issue is that I would like to be able to pass the data to the corresponding session for that message, like in the following pseudocode, but the session is not available in UniversalBot.use. Does anyone have any ideas?
bot.use({
receive: function (event, next) {
if(event.sourceEvent.postback.referral.ref) {
session.userData.ref = event.sourceEvent.postback.referral.ref; // won't work
} else {
next();
}
});
This was quite easy in the end -- just needed to read the api for bot.use and middleware a little more closely. Here's my solution below. See also.
bot.use({
botbuilder: function (session, next) {
var event = session.message;
// check for referral
if(event.sourceEvent.postback && event.sourceEvent.postback.referral) {
session.userData.referral = event.sourceEvent.postback.referral.ref;
} else if (event.sourceEvent.referral) {
session.userData.referral = event.sourceEvent.referral;
}
session.save();
next();
}
});
How do we achieve this from a C# bot?
@haligasd you can use IPostToBot as a type of receive middleware, or use IActivityLogger to inspect all activities.
@bmperrea this solution crashes because on the emulator sourceEvent seems to be null :) just a headsup, you should probably check if(event && event.sourceEvent && event.sourceEvent.postback)
@bmperrea Great solution thanks! However it only works for me for users that have interacted with the bot before. Not for totally new users??? Do you have the same issue?
@willportnoy is it a good idea to use Scorables in C# instead of the IActivityLogger, and is there an example for "IPostToBot as a type of receive middleware"
@etbuilder
LogPostToBot is registered with autofac as a keyed type: https://github.com/Microsoft/BotBuilder/blob/31048a2173313c81a2db47efce6a8a869b4ec284/CSharp/Library/Microsoft.Bot.Builder.Autofac/Dialogs/DialogModule.cs#L349
This enables supplying a custom IPostToBot:
Conversation.UpdateContainer(
builder =>
{
builder.RegisterType<ActivityLogger>().AsImplementedInterfaces().InstancePerDependency();
builder
.RegisterType<InterceptLogPostToBot>()
.Keyed<IPostToBot>(typeof(LogPostToBot));
});
public class InterceptLogPostToBot: IPostToBot
{
private readonly IPostToBot inner;
private readonly IActivityLogger logger;
public InterceptLogPostToBot(IPostToBot inner, IActivityLogger logger)
{
SetField.NotNull(out this.inner, nameof(inner), inner);
SetField.NotNull(out this.logger, nameof(logger), logger);
}
async Task IPostToBot.PostAsync(IActivity activity, CancellationToken token)
{
//do something before calling the logger
await this.logger.LogAsync(activity);
await inner.PostAsync(activity, token);
}
}
Most helpful comment
This was quite easy in the end -- just needed to read the api for
bot.useand middleware a little more closely. Here's my solution below. See also.bot.use({ botbuilder: function (session, next) { var event = session.message; // check for referral if(event.sourceEvent.postback && event.sourceEvent.postback.referral) { session.userData.referral = event.sourceEvent.postback.referral.ref; } else if (event.sourceEvent.referral) { session.userData.referral = event.sourceEvent.referral; } session.save(); next(); } });