Botkit: Handling payload from Messenger buttons

Created on 23 Nov 2016  路  10Comments  路  Source: howdyai/botkit

How to handle the payload from a messenger button-template and direct to the related next step?

In my code, the response is not heard by the bot when clicking the button, I think I am missing a step to handle the response there:

        }, function(response, convo) {
            convo.next();
        });

Full block

bot.setGetStartedPayload('start',  function() {});

controller.hears('start', 'message_received', function(bot, message)  {

     bot.startConversation(message, function(err, convo) {
        convo.say('Hi!');
        convo.ask({
            attachment: {
                'type': 'template',
                'payload': {
                    'template_type': 'button',
                    'text': "my question",
                    'buttons': [
                        {
                            'type': 'postback',
                            'title': 'answer 1',
                            'payload': 'answer1',
                        },
                        {
                            'type': 'postback',
                            'title': 'answer 2',
                            'payload': 'answer2',
                        }
                    ]  
                }
            }
        }, function(response, convo) {
            convo.next();
        });
    });
});



controller.hears('answer1', 'message_received', function(bot, message)  {

     bot.startConversation(message, function(err, convo) {
        convo.say('you said answer 1?');
Facebook-related help wanted

Most helpful comment

I think you would be better off using the pattern and actions approach here instead of the switch, it would also make much more sense and keep everything more organized. Do not get scared if it adds more lines to your code.

This is what i am talking about:

convo.ask('Some question OR your message object/facebook attachment', [
                            {
                                pattern: 'yes',
                                callback: function(response, convo) {
                                    // since no further messages are queued after this,
                                    // the conversation will end naturally with status == 'completed'
                                    convo.next();
                                }
                            },
                            {
                                pattern: 'no',
                                callback: function(response, convo) {
                                    // stop the conversation. this will cause it to end with status == 'stopped'
                                    convo.stop();
                                }
                            },
                            {
                                default: true,
                                callback: function(response, convo) {
                                    convo.repeat();
                                    convo.next();
                                }
                            }
]);

or using threads:

convo.addQuestion('another question or facebook attachment?', [
    {
        pattern: 'yes',
        callback: function(response, convo) {
            convo.gotoThread('correct');
        }
    },
    {
        pattern: 'quit',
        callback: function(response, convo) {
            convo.stop();
        }
    },
    {
        default: true,
        callback: function(response, convo) {
            convo.gotoThread('incorrect');
        }
    }
],{key: 'answer'},'default'); // this question has been added to the default thread

//because of the action completed the convo will receive the completed event and end with success
convo.addMessage({
    text: 'Hell yeah!',
    action: 'completed'
},'correct');

// set up incorrect thread and then go back to the default thread (action:'default')

convo.addMessage({
    text: 'Its not the answer im looking for',
    action: 'default'
}, 'incorrect');

Maybe they will give you some ideas.

I hope it helps.

Alex

All 10 comments

My solution at present is to use the convo_bot.js pattern with a switch statement, but feels like this is overkill.
Please any advice?

Can you be more specific please, as i might have done this. Try and explain exactly what you are trying to do and please include more code, not just pieces.

My Messenger bot sends a button_template to the user. Depending on his choice (the user wants to order or needs additional information), the user is directed to a different card. Here is how I do it:

controller.hears('start', 'message_received', function(bot, message)  {
  bot.startConversation(message, askMotive);
});

askMotive = function(response, convo) {
  convo.ask({
            attachment: {
                'type': 'template',
                'payload': {
                    'template_type': 'button',
                    'text': "What do you want?",
                    'buttons': [
                        {
                            'type': 'postback',
                            'title': 'order pizza',
                            'payload': 'order',
                        },
                        {
                            'type': 'postback',
                            'title': 'get info',
                            'payload': 'info',
                        }
                    ]  
                }
            }
        }, function(response, convo) {
    convo.say("Awesome.");
    switch(response.text) {
        case "info":
        info(response, convo);
        break;
        case "order":
        order(response, convo);
        break;
        default:
        info(response, convo);
    }
    convo.next();
  });
};

info = function(response, convo) {
  convo.ask("what do you need to know more about?", function(response, convo) {
    convo.say("Ok.")
    apply(response, convo);
    convo.next();
  });
};

order = function(response, convo) { 
  convo.ask("What size do you want?", function(response, convo) {
    convo.say("Ok!");
    convo.next();
  });
};

Do I really need the switch statement to do this or is there a more straight forward option?

You can also use:

controller.on('facebook_postback', function(bot, message) {
    bot.reply(message, 'This is the payload selected: ' + message.payload);
});

And handle it there based on the payload. Does this help?

Alex

Thanks Alex. I'm reluctant to using the controller.on as I worry this will add complexity to mongo storage.

My bot is very straight forward (only buttons, no free text, no a.i., the conversation is scripted form A to Z in a gamebook manner), so I could do with convo.say and convo.ask only (in my code above). I suspect this will ease the process of storing all user's responses. How would you advise?

If not, I will go with the lighter controller.on you recommend.

I think you would be better off using the pattern and actions approach here instead of the switch, it would also make much more sense and keep everything more organized. Do not get scared if it adds more lines to your code.

This is what i am talking about:

convo.ask('Some question OR your message object/facebook attachment', [
                            {
                                pattern: 'yes',
                                callback: function(response, convo) {
                                    // since no further messages are queued after this,
                                    // the conversation will end naturally with status == 'completed'
                                    convo.next();
                                }
                            },
                            {
                                pattern: 'no',
                                callback: function(response, convo) {
                                    // stop the conversation. this will cause it to end with status == 'stopped'
                                    convo.stop();
                                }
                            },
                            {
                                default: true,
                                callback: function(response, convo) {
                                    convo.repeat();
                                    convo.next();
                                }
                            }
]);

or using threads:

convo.addQuestion('another question or facebook attachment?', [
    {
        pattern: 'yes',
        callback: function(response, convo) {
            convo.gotoThread('correct');
        }
    },
    {
        pattern: 'quit',
        callback: function(response, convo) {
            convo.stop();
        }
    },
    {
        default: true,
        callback: function(response, convo) {
            convo.gotoThread('incorrect');
        }
    }
],{key: 'answer'},'default'); // this question has been added to the default thread

//because of the action completed the convo will receive the completed event and end with success
convo.addMessage({
    text: 'Hell yeah!',
    action: 'completed'
},'correct');

// set up incorrect thread and then go back to the default thread (action:'default')

convo.addMessage({
    text: 'Its not the answer im looking for',
    action: 'default'
}, 'incorrect');

Maybe they will give you some ideas.

I hope it helps.

Alex

addMessage and addQuestion can contain message objects exactly like ask() and say() so facebook payloads can be used as well, not just text.

Like so:

convo.addMessage({
    attachment:{
        'type':'image',
        'payload':{
            'url':'https://media.giphy.com/media/3o6ozzc24Ikxi1WXo4/giphy.gif'
        }
    },
    action: 'default'
},'incorrect');

Thanks for the heads up Alex! Threads work great as well.

Could you elaborate what are the advantage of using threads over switch statements? Seems to comes down to the same result but maybe i'm missing something.

Its not a huge difference, its just that with threads you can access them form anywhere in the convo once they are setup. I feel its a bit more logical to use stuff that is built-in for that purpose.

Patterns and actions were built for this purpose, to match the response and then to execute the appropriate callback.

In the end it comes down to personal preference. Whatever works for you and what is easier for you to maintain and understand.

Alex

Follow-up: I've been trying the build-in threads but finally moved back to switch statements. Eventually I feel I get more clarity and more simplicity with them (also, threads do add many lines to the code as well).
I will update here if I encounter any limitation with switch statement.
Thanks Alex!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iworkforthem picture iworkforthem  路  3Comments

stelio picture stelio  路  4Comments

GautierT picture GautierT  路  3Comments

dfischer picture dfischer  路  4Comments

znat picture znat  路  4Comments