CaptainPlanet
CaptainPlanet

Reputation: 382

How to catch Facebook messaging_optins with Azure Bot Channels Registration + Botbuilder SDK?

I've got a chatbot up and running, built using Node.JS Microsoft Bot Framework, and deployed to an Azure server as a Web App, with a Bot Channels Registration resource as the frontend endpoint.

This Bot Channels Registration is connected to Facebook Messenger (via a FB App) - meaning, the webhook for the Facebook App points to https://facebook.botframework.com/api/v1/bots/<BOT_CHANNELS_REGISTRATION_RESOURCE_NAME>.

This all works well for normal chat functionality.

However, I'd now like to add an opt-in checkbox to a separate web page I have. This checkbox works by pinging FB, which then sends a very specific payload to the already configured bot webhook.

{
  "recipient":{
    "id":"<PAGE_ID>"
  },
  "timestamp":<UNIX_TIMESTAMP>,
  "optin":{
    "ref":"<PASS_THROUGH_PARAM>",
    "user_ref":"<UNIQUE_REF_PARAM>"
  }
}

My question is this:

How does the Bot Channels Registration receive and handle the above payload? Will it just automatically forward it to the Messaging Endpoint I have configured in the Bot Channels Registration settings? Or will it get stuck, and never reach my actual bot Web App?

Finally, if it does reach my normal messages endpoint, how can I handle the specific payload with my botbuilder.ChatConnector() listener? Given that my web app code looks like (in essence)

var restify = require('restify');
var builder = require('botbuilder');
var dialogues = require('./dialogues');

var chatbot = function (config) {
    var bot = {};
    chatbot.listen = function () {
        var stateStorage = new builder.MemoryBotStorage();

        var connector = new builder.ChatConnector({
            appId: process.env.APP_ID,
            appPassword: process.env.APP_PASSWORD
        });

        bot = new builder.UniversalBot(connector, function (session) {
            session.beginDialog(dialogues.base(bot).name);
        }).set('storage', stateStorage);

        return connector.listen();
    };

    return chatbot;
}

var server = restify.createServer();

// Listen for messages from users 
server.post('/api/messages', chatbot.listen());

server.listen(process.env.port, function () {
    console.log('%s listening to %s', server.name, server.url);
});

Thanks!

EDIT: I've figured out how to handle the above payload within my messaging endpoint - by adding a server.pre() handler to my server, e.g.

server.pre(function (req, res, next) {
    if (req.body && req.body.optin_payload_specific_field){
        // handle opt-in payload
    } else {
        return next();
    }
});

However, via extra logging lines, it seems the opt-in payload isn't even making it to this endpoint. It seems to be stopped within the Bot Channels Registration. Currently looking for a way to resolve that major roadblock.

Upvotes: 0

Views: 391

Answers (1)

CaptainPlanet
CaptainPlanet

Reputation: 382

So, per @JJ_Wailes investigation, it seems like this is not a supported feature (in fact, it's a current feature request). See his comments on the original post for more details.

However, I did find a half-workaround to capture the user_ref identifier generated by the checkbox_plugin, for those interested:

1) From your external site, follow the steps from the documentation here for sending the initial user_ref to FB. FB will then make a callout to your bot, but per the above, that gets blocked by the Bot Channels Registration piece, so it's ignored.

2) From that same external site, use the user_ref to send a message to the user (just using the normal requests library). A successful send means that the user_ref was properly registered in FB by that step #1 call - a failure means you'll need to repeat step #1 (or use some other error handling flow).

3) After that, the next time the user responds to your bot in FB (as long as you don't send any other messages to them), the message your bot will receive will contain this as part of the payload:

{ ...
  channelData:
    { ...
      prior_message:
        { source: 'checkbox_plugin',
          identifier: <user_ref> }
    }
}

So I've currently added a check within my bot.use(), where if that section is present in the incoming message payload (session.message.sourceEvent.prior_message) and the source is "checkbox_plugin", I store the corresponding user_ref in the session.userData, and can work from there.

I would love to see this feature added into the supported Azure bot stack, but in the meantime hopefully this helps anyone else encountering this (admittedly niche) hurdle.

Upvotes: 2

Related Questions