• Stars
    star
    961
  • Rank 47,587 (Top 1.0 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 8 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Definitely the best way to make Bots on Facebook Messenger with Ruby

Gem Version Gem Downloads Build Status Code Climate Coverage Status Documentation Coverage

Installation

$ gem install facebook-messenger

Usage

Sending and receiving messages

You can reply to messages sent by the human:

# bot.rb
require 'facebook/messenger'

Facebook::Messenger::Bot.on :message do |message|
  message.id          # => 'mid.1457764197618:41d102a3e1ae206a38'
  message.sender      # => { 'id' => '1008372609250235' }
  message.recipient   # => { 'id' => '2015573629214912' }
  message.seq         # => 73
  message.sent_at     # => 2016-04-22 21:30:36 +0200
  message.text        # => 'Hello, bot!'
  message.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]

  message.reply(text: 'Hello, human!')
end

... or even send the human messages out of the blue:

Facebook::Messenger::Bot.deliver({
  recipient: {
    id: YOUR_RECIPIENT_ID
  },
  message: {
    text: 'Human?'
  },
  messaging_type: Facebook::Messenger::Bot::MessagingType::UPDATE
}, page_id: YOUR_PAGE_ID)
Messages with images

The human may require visual aid to understand:

message.reply(
  attachment: {
    type: 'image',
    payload: {
      url: 'http://sky.net/visual-aids-for-stupid-organisms/pig.jpg'
    }
  }
)
Messages with quick replies

The human may appreciate hints:

message.reply(
  text: 'Human, who is your favorite bot?',
  quick_replies: [
    {
      content_type: 'text',
      title: 'You are!',
      payload: 'HARMLESS'
    }
  ]
)
Messages with buttons

The human may require simple options to communicate:

message.reply(
  attachment: {
    type: 'template',
    payload: {
      template_type: 'button',
      text: 'Human, do you like me?',
      buttons: [
        { type: 'postback', title: 'Yes', payload: 'HARMLESS' },
        { type: 'postback', title: 'No', payload: 'EXTERMINATE' }
      ]
    }
  }
)

When the human has selected an option, you can act on it:

Bot.on :postback do |postback|
  postback.sender    # => { 'id' => '1008372609250235' }
  postback.recipient # => { 'id' => '2015573629214912' }
  postback.sent_at   # => 2016-04-22 21:30:36 +0200
  postback.payload   # => 'EXTERMINATE'

  if postback.payload == 'EXTERMINATE'
    puts "Human #{postback.recipient} marked for extermination"
  end
end

See Facebook's documentation for all message options.

Reactions

Humans have feelings, and they can react to your messages. You can pretend to understand:

Bot.on :reaction do |message|
  message.emoji # => "👍"
  message.action # => "react"
  message.reaction # => "like"

  message.reply(text: 'Your feelings have been registered')
end
Typing indicator

Show the human you are preparing a message for them:

Bot.on :message do |message|
  message.typing_on

  # Do something expensive

  message.reply(text: 'Hello, human!')
end

Or that you changed your mind:

Bot.on :message do |message|
  message.typing_on

  if # something
    message.reply(text: 'Hello, human!')
  else
    message.typing_off
  end
end
Mark as viewed

You can mark messages as seen to keep the human on their toes:

Bot.on :message do |message|
  message.mark_seen
end
Record messages

You can keep track of messages sent to the human:

Facebook::Messenger::Bot.on :message_echo do |message_echo|
  message_echo.id          # => 'mid.1457764197618:41d102a3e1ae206a38'
  message_echo.sender      # => { 'id' => '1008372609250235' }
  message_echo.seq         # => 73
  message_echo.sent_at     # => 2016-04-22 21:30:36 +0200
  message_echo.text        # => 'Hello, bot!'
  message_echo.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]

  # Log or store in your storage method of choice (skynet, obviously)
end
Record accepted message requests

You can keep track of message requests accepted by the human:

Bot.on :message_request do |message_request|
  message_request.accept? # => true

  # Log or store in your storage method of choice (skynet, obviously)
end
Record instant game progress

You can keep track of instant game progress:

Bot.on :game_play do |game_play|
  game_play.sender    # => { 'id' => '1008372609250235' }
  game_play.recipient # => { 'id' => '2015573629214912' }
  game_play.sent_at   # => 2016-04-22 21:30:36 +0200
  game_play.game      # => "<GAME-APP-ID>"
  game_play.player    # => "<PLAYER-ID>"
  game_play.context   # => { 'context_type' => "<CONTEXT-TYPE:SOLO|THREAD>", 'context_id' => "<CONTEXT-ID>" }
  game_play.score     # => 100
  game_play.payload   # => "<PAYLOAD>"
end

Send to Facebook

When the human clicks the Send to Messenger button embedded on a website, you will receive an optin event.

Bot.on :optin do |optin|
  optin.sender    # => { 'id' => '1008372609250235' }
  optin.recipient # => { 'id' => '2015573629214912' }
  optin.sent_at   # => 2016-04-22 21:30:36 +0200
  optin.ref       # => 'CONTACT_SKYNET'

  optin.reply(text: 'Ah, human!')
end

Message delivery receipts

You can stalk the human:

Bot.on :delivery do |delivery|
  delivery.ids       # => 'mid.1457764197618:41d102a3e1ae206a38'
  delivery.sender    # => { 'id' => '1008372609250235' }
  delivery.recipient # => { 'id' => '2015573629214912' }
  delivery.at        # => 2016-04-22 21:30:36 +0200
  delivery.seq       # => 37

  puts "Human was online at #{delivery.at}"
end

Referral

When the human follows a m.me link with a ref parameter like http://m.me/mybot?ref=myparam, you will receive a referral event.

Facebook::Messenger::Bot.on :referral do |referral|
  referral.sender    # => { 'id' => '1008372609250235' }
  referral.recipient # => { 'id' => '2015573629214912' }
  referral.sent_at   # => 2016-04-22 21:30:36 +0200
  referral.ref       # => 'MYPARAM'
end

Pass thread control

Another bot can pass a human to you:

Facebook::Messenger::Bot.on :pass_thread_control do |pass_thread_control|
  pass_thread_control.new_owner_app_id # => '123456789'
  pass_thread_control.metadata # => 'Additional content that the caller wants to set'
end

Change messenger profile

You can greet new humans to entice them into talking to you, in different locales:

Facebook::Messenger::Profile.set({
  greeting: [
    {
      locale: 'default',
      text: 'Welcome to your new bot overlord!'
    },
    {
      locale: 'fr_FR',
      text: 'Bienvenue dans le bot du Wagon !'
    }
  ]
}, page_id: YOUR_PAGE_ID)

You can define the action to trigger when new humans click on the Get Started button. Before doing it you should check to select the messaging_postbacks field when setting up your webhook.

Facebook::Messenger::Profile.set({
  get_started: {
    payload: 'GET_STARTED_PAYLOAD'
  }
}, page_id: YOUR_PAGE_ID) 

You can show a persistent menu to humans.

Facebook::Messenger::Profile.set({
  persistent_menu: [
    {
      locale: 'default',
      composer_input_disabled: true,
      call_to_actions: [
        {
          title: 'My Account',
          type: 'nested',
          call_to_actions: [
            {
              title: 'What is a chatbot?',
              type: 'postback',
              payload: 'EXTERMINATE'
            },
            {
              title: 'History',
              type: 'postback',
              payload: 'HISTORY_PAYLOAD'
            },
            {
              title: 'Contact Info',
              type: 'postback',
              payload: 'CONTACT_INFO_PAYLOAD'
            }
          ]
        },
        {
          type: 'web_url',
          title: 'Get some help',
          url: 'https://github.com/jgorset/facebook-messenger',
          webview_height_ratio: 'full'
        }
      ]
    },
    {
      locale: 'zh_CN',
      composer_input_disabled: false
    }
  ]
}, page_id: YOUR_PAGE_ID)

Handle a Facebook Policy Violation

See Facebook's documentation on Messaging Policy Enforcement

Facebook::Messenger::Bot.on :'policy_enforcement' do |referral|
  referral.action # => 'block'
  referral.reason # => "The bot violated our Platform Policies (https://developers.facebook.com/policy/#messengerplatform). Common violations include sending out excessive spammy messages or being non-functional."
end

messaging_type

Sending Messages

See Facebook's documentation on Sending Messages

As of May 7th 2018 all messages are required to include a messaging_type

Facebook::Messenger::Bot.deliver({
  recipient: {
    id: '45123'
  },
  message: {
    text: 'Human?'
  },
  messaging_type: Facebook::Messenger::Bot::MessagingType::UPDATE
}, page_id: YOUR_PAGE_ID)
MESSAGE_TAG

See Facebook's documentation on Message Tags

When sending a message with messaging_type: MESSAGE_TAG (Facebook::Messenger::Bot::MessagingType::MESSAGE_TAG) you must ensure you add a tag: parameter

Facebook::Messenger::Bot.deliver({
  recipient: {
    id: '45123'
  },
  message: {
    text: 'Human?'
  },
  messaging_type: Facebook::Messenger::Bot::MessagingType::MESSAGE_TAG
  tag: Facebook::Messenger::Bot::Tag::NON_PROMOTIONAL_SUBSCRIPTION
}, page_id: YOUR_PAGE_ID) 

Configuration

Create an Application on Facebook

Follow the Quick Start guide to create an Application on Facebook.

Make a configuration provider

Use the generated access token and your verify token to configure your bot. Most bots live on a single Facebook Page. If that is the case with yours, too, just set these environment variables and skip to the next section:

export ACCESS_TOKEN=EAAAG6WgW...
export APP_SECRET=a885a...
export VERIFY_TOKEN=95vr15g...

If your bot lives on multiple Facebook Pages, make a configuration provider to keep track of access tokens, app secrets and verify tokens for each of them:

class ExampleProvider < Facebook::Messenger::Configuration::Providers::Base
  # Verify that the given verify token is valid.
  #
  # verify_token - A String describing the application's verify token.
  #
  # Returns a Boolean representing whether the verify token is valid.
  def valid_verify_token?(verify_token)
    bot.exists?(verify_token: verify_token)
  end

  # Find the right application secret.
  #
  # page_id - An Integer describing a Facebook Page ID.
  #
  # Returns a String describing the application secret.
  def app_secret_for(page_id)
    bot.find_by(page_id: page_id).app_secret
  end

  # Find the right access token.
  #
  # recipient - A Hash describing the `recipient` attribute of the message coming
  #             from Facebook.
  #
  # Note: The naming of "recipient" can throw you off, but think of it from the
  # perspective of the message: The "recipient" is the page that receives the
  # message.
  #
  # Returns a String describing an access token.
  def access_token_for(recipient)
    bot.find_by(page_id: recipient['id']).access_token
  end

  private

  def bot
    MyApp::Bot
  end
end

Facebook::Messenger.configure do |config|
  config.provider = ExampleProvider.new
end

You can get the current configuration provider with Facebook::Messenger.config.provider.

Subscribe your Application to a Page

Once you've configured your bot, subscribe it to the Page to get messages from Facebook:

Facebook::Messenger::Subscriptions.subscribe(
  access_token: access_token,
  subscribed_fields: %w[feed mention name]
)

You only need to subscribe your page once. As long as your bot works and responds to Messenger's requests in a timely fashion it will remain subscribed, but if your bot crashes or otherwise becomes unavailable Messenger may unsubscribe it and you'll have to subscribe again.

Run it

... on Rack

The bot runs on Rack, so you hook it up like you would an ordinary web application:

# config.ru
require 'facebook/messenger'
require_relative 'bot'

run Facebook::Messenger::Server

# or Facebook::Messenger::ServerNoError for dev
$ rackup
... on Rails

Rails doesn't give you much that you'll need for a bot, but if you have an existing application that you'd like to launch it from or just like Rails a lot, you can mount it:

# config/routes.rb

Rails.application.routes.draw do
  # ...

  mount Facebook::Messenger::Server, at: 'bot'
end

We suggest that you put your bot code in app/bot.

# app/bot/example.rb

include Facebook::Messenger

Faceboook::Messenger::Bot.on :message do |message|
  message.reply(text: 'Hello, human!')
end

Remember that Rails only eager loads everything in its production environment. In the development and test environments, it only requires files as you reference constants. You'll need to explicitly load app/bot, then:

# config/initializers/bot.rb
unless Rails.env.production?
  bot_files = Dir[Rails.root.join('app', 'bot', '**', '*.rb')]
  bot_reloader = ActiveSupport::FileUpdateChecker.new(bot_files) do
    bot_files.each{ |file| require_dependency file }
  end

  ActiveSupport::Reloader.to_prepare do
    bot_reloader.execute_if_updated
  end

  bot_files.each { |file| require_dependency file }
end

And add below code into config/application.rb to ensure rails knows bot files.

# Auto-load the bot and its subdirectories
config.paths.add File.join('app', 'bot'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'bot', '*')]

Test it...

...locally

To test your locally running bot, you can use ngrok. This will create a secure tunnel to localhost so that Facebook can reach the webhook.

... with RSpec

In order to test that behaviour when a new event from Facebook is registered, you can use the gem's trigger method. This method accepts as its first argument the type of event that it will receive, and can then be followed by other arguments that mock objects received from Messenger. Using Ruby's Struct class can be very useful for creating these mock objects.

In this case, subscribing to Messenger events has been extracted into a Listener class.

# app/bot/listener.rb
require 'facebook/messenger'

include Facebook::Messenger

class Listener
  Facebook::Messenger::Subscriptions.subscribe(
    access_token: ENV['ACCESS_TOKEN'],
    subscribed_fields: %w[feed mention name]
  )

  Bot.on :message do |message|
    Bot.deliver({
      recipient: message.sender,
      message: {
        text: 'Uploading your message to skynet.'
      }
    }, access_token: ENV['ACCESS_TOKEN'])
  end
end

Its respective test file then ensures that the Bot object receives a call to deliver. This is just a basic test, but check out the RSpec docs for more information on testing with RSpec.

require 'rails_helper'

RSpec.describe Listener do
  FakeMessage = Struct.new(:sender, :recipient, :timestamp, :message)

  describe 'Bot#on(message)' do
    it 'responds with a message' do
      expect(Bot).to receive(:deliver)
      Bot.trigger(:message, fake_message)
    end
  end

  private

  def fake_message
    sender = {"id"=>"1234"}
    recipient = {"id"=>"5678"}
    timestamp = 1528049653543
    message = {"text"=>"Hello, world"}
    FakeMessage.new(sender, recipient, timestamp, message)
  end
end

Development

After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.

Run rspec to run the tests, rubocop to lint, or rake to do both.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/jgorset/facebook-messenger.

Projects using Facebook Messenger

  • Rubotnik is a boilerplate for Facebook Messenger, and a great place to start if you're new to bots.

  • Chatwoot use Facebook Messenger to integrate their customer support bots with, well, Facebook Messenger.

  • Botamp is the all-in-one solution for Marketing Automation via messaging apps.

I love you

Johannes Gorset made this. You should tweet me if you can't get it to work. In fact, you should tweet me anyway.

I love Schibsted

I work at Schibsted Products & Technology with a bunch of awesome folks who are every bit as passionate about building things as I am. If you're using Facebook Messenger, you should probably join us.

More Repositories

1

facepy

Facepy makes it really easy to use Facebook's Graph API with Python
Python
863
star
2

django-kronos

Kronos makes it really easy to define and schedule tasks with cron
Python
315
star
3

fandjango

Fandjango makes it really easy to create Facebook applications with Django
Python
253
star
4

git.io

Command-line client for GitHub's URL shortener
Ruby
76
star
5

django-shortcuts

You spend too much time typing "python manage.py"
Python
62
star
6

Recorder

Record and play audio in Swift (and more easily than with AVFoundation)
Swift
37
star
7

django-respite

Respite conforms Django to Representational State Transfer (and, incidentally, HTTP)
Python
34
star
8

facebook

Facebook makes it even easier to interact with Facebook's Graph API
Python
22
star
9

fandjango-example

Example Facebook application powered by Fandjango
Python
19
star
10

label

Label describes the gems in your Gemfile so you don't have to look them up to see what they do
Ruby
19
star
11

push-it

Remember to push by the power of '80s classics
Shell
16
star
12

python-package-template

Minimal template for developing packages for Python
Python
11
star
13

discotech

Command lines can be bleak... disco time!
Ruby
11
star
14

meem

Meem is a command-line tool to create memes. It's pretty awesome.
Ruby
9
star
15

lean-coffee

Lean Coffee for distributed teams
Ruby
8
star
16

starred

Plays a victory fanfare when your repositories get starred on GitHub
JavaScript
8
star
17

john-terjify

Chrome extension that replaces "he" and "she" with "John Terje".
JavaScript
7
star
18

garble

Garble replaces words with synonyms
Ruby
7
star
19

adam

Adam is a library for all things EVE.
Ruby
5
star
20

reraises

Reraise an exception as another
Ruby
5
star
21

jjjaaa

JJJAAA
Ruby
4
star
22

jquery-placeholder

HTML5 placeholder emulation for older browsers
JavaScript
4
star
23

custodian

Lightweight resource monitor
Ruby
4
star
24

node-chat-server

Everyone has made a chat server in Node.js. This is mine.
JavaScript
3
star
25

lab

Command-line client for GitLab
Ruby
3
star
26

can-i-hack-database

The database powering "can I hack".
3
star
27

search

A file search and suggestion command
Ruby
3
star
28

github-commits-by-repository

A script to show commits for a given user, grouped by repository
JavaScript
2
star
29

cushion

Command-line Custodian client
Ruby
2
star
30

kingpin

Do-It-Yourself Heroku
Ruby
2
star
31

tig-dotfiles

2
star
32

whats-new-in-rails-4.1

My talk on Rails 4.1 for Hyper's Ruby meetup
Ruby
2
star
33

tmux-dotfiles

These are my TMUX dotfiles. I like them.
2
star
34

zsh-dotfiles

These are my zsh dotfiles. I like them.
Shell
2
star
35

jquery-wizard

jQuery Wizard turns your forms into beautiful wizards without cluttering your markup.
JavaScript
2
star
36

whisper-benchmarks

Python
1
star
37

vim-dotfiles

These are my VIM dotfiles. I like them.
Vim Script
1
star
38

Shame-Nun

Swift
1
star
39

jquery-collapsible

Collapse and expand DOM elements
JavaScript
1
star
40

jquery-table-of-contents

Table of Contents renders a table of contents for a given section of the document.
JavaScript
1
star
41

battlefield-timer

Respawn timers for vehicles in Battlefield 4
Ruby
1
star