MessageQuickly
This gem is a lightweight solution to integrate Facebook's Messenger Platform into your rails app, allowing you to create bots to facilitate conversations with people on Facebook Messenger. It includes a mountable rails engine to handle webhooks, and a simple client to talk to the Send API.
We also have an accompanying demo app.
Installation
Add this to your Gemfile, and then bundle install
:
gem 'message_quickly'
Generate the page access token on the developer portal, which will allow you to start using the APIs:
With the token, make sure to run this:
curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<page access token>"
Create the following environment variables:
FACEBOOK_APP_ID=<facebook app id goes here>
FACEBOOK_PAGE_ID=<your facebook page id>
FACEBOOK_MESSENGER_VERIFICATION_TOKEN=my_voice_is_my_password_verify_me
FACEBOOK_MESSENGER_PAGE_ACCESS_TOKEN=<generate this on the developer portal>
You will need to run your app, and make it accessible to the developer portal now, so run your server:
rails server
Use something like Burrow to provide access to your localhost:
Go to your Facebook App page in the developer portal, and use the above verification token like so:
Facebook will then verify with the mounted engine, and you're all set.
Notes
Messenger Platform is designed to handle webhooks in background jobs on ActiveJob, so you should set up a queuing backend (e.g. Sidekiq) and configure ActiveJob to use it.
Your app is required to be served over HTTPS. When working locally, I used the default WEBrick server as it supports HTTPS connections out of the box.
Usage
There are two parts to this gem: handling webhooks (which is what the rails engine is for), and calling the Send API.
Additionally, there are some helpers for working with messenger plugins.
Webhooks
Webhooks allow the Facebook Messenger Platform to talk to your app. For example, you will receive a request on your webhook when a user authenticates or messages your Facebook page/app.
Mount the engine in your routes.rb
(/webhook
is used in the examples):
mount MessageQuickly::Engine, at: "/webhook"
Generate the callback files:
rails generate message_quickly:callbacks
When you run rails generate callbacks
, four files will be created for you. They look something like this:
class AuthenticationCallback < MessageQuickly::Callback
def callback_name
:messaging_optins
end
def run(event, json)
# for e.g.
# puts event.text
end
end
All you need to do is make sure your app is available publicly, and to fill up the run
method. All the four callbacks defined in the platform are supported this way:
Webhook Name | Callback Class | Description |
---|---|---|
messaging_optins | AuthenticationCallback | Subscribes to authentication callbacks via the Send-to-Messenger Plugin |
messages | MessageReceivedCallback | Subscribes to message-received callbacks |
message_deliveries | MessageDeliveredCallback | Subscribes to message-delivered callbacks |
message_reads | MessageReadCallback | Subscribes to message read callbacks |
messaging_postbacks | PostbackCallback | Subscribes to postback callbacks |
account_linking | AccountLinkingCallback | Subscribes to account linking callbacks |
Send API
By default, the API client will be created for you, and is accessible at:
MessageQuickly::Api::Base.client
This makes use of the environment variables FACEBOOK_MESSENGER_PAGE_ACCESS_TOKEN
and FACEBOOK_MESSENGER_PAGE_ID
.
If you would like to use different sets of credentials in the app, you can create your own clients like so:
send_api_client = MessageQuickly::Api::Client.new do |client|
client.page_access_token = '<page access token goes here>'
client.page_id = '<page id goes here>'
end
MessageQuickly::Api::UserProfile.new(send_api_client).find('<fb page specific user id here>')
Looking up a user's profile
Do note that we are using the default client, which is loaded automatically by default.
MessageQuickly::Api::UserProfile.find('<fb page specific user id here>')
Creating a recipient object
You can create a recipient with either an id
, or a phone_number
. If both are provided, messages will be sent via the id
.
recipient = MessageQuickly::Messaging::Recipient.new(id: '123')
recipient = MessageQuickly::Messaging::Recipient.new(id: '123', phone_number: '+1(212)555-2368')
Sending a simple text message
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.text = 'Hello'
end
Sending image attachments
You can either send an image attachment as a URL:
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.build_attachment(:image) { |attachment| attachment.url = 'http://placehold.it/350x150' }
end
Or you can send it as a file:
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.build_attachment(:image) do |attachment|
attachment.file = "spec/fixtures/12057251_909506139117248_2059695706_n.png"
attachment.file_type = 'image/png'
end
end
Sending a generic template attachment
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.build_attachment(:generic_template) do |template|
template.build_element do |element|
element.title = "Classic White T-Shirt"
element.image_url = 'http://petersapparel.parseapp.com/img/item100-thumb.png'
element.subtitle = 'Soft white cotton t-shirt is back in style'
element.build_button(:web_url) do |button|
button.url = "https://petersapparel.parseapp.com/view_item?item_id=100"
button.title = "View Item"
end
element.build_button(:web_url) do |button|
button.url = "https://petersapparel.parseapp.com/buy_item?item_id=100"
button.title = "Buy Item"
end
element.build_button(:postback) do |button|
button.payload = "USER_DEFINED_PAYLOAD_FOR_ITEM100"
button.title = "Bookmark Item"
end
end
template.build_element do |element|
element.title = "Classic Grey T-Shirt"
element.image_url = 'http://petersapparel.parseapp.com/img/item101-thumb.png'
element.subtitle = 'Soft gray cotton t-shirt is back in style'
element.build_button(:web_url) do |button|
button.url = "https://petersapparel.parseapp.com/view_item?item_id=101"
button.title = "View Item"
end
element.build_button(:web_url) do |button|
button.url = "https://petersapparel.parseapp.com/buy_item?item_id=101"
button.title = "Buy Item"
end
element.build_button(:postback) do |button|
button.payload = "USER_DEFINED_PAYLOAD_FOR_ITEM101"
button.title = "Bookmark Item"
end
end
end
end
Sending a button template attachment
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.build_attachment(:button_template) do |template|
template.text = 'How are you doing today?'
template.build_button(:web_url) do |button|
button.url = 'https://petersapparel.parseapp.com'
button.title = 'Show Website'
end
template.build_button(:postback) do |button|
button.payload = 'USER_DEFINED_PAYLOAD'
button.title = 'Start Chatting'
end
end
end
Sending an account linking button
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.build_attachment(:button_template) do |template|
template.text = 'Please log in'
template.build_button(:account_link) do |button|
button.url = 'https://www.example.com/oauth/authorize'
end
end
end
Sending a receipt template attachment
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.build_attachment(:receipt_template) do |template|
template.recipient_name = 'Stephane Crozatier'
template.order_number = (0...50).map { ('a'..'z').to_a[rand(26)] }.join
template.currency = 'USD'
template.payment_method = 'Visa 2345'
template.order_url = 'http://petersapparel.parseapp.com/order?order_id=123456'
template.timestamp = '1428444852'
template.build_element do |element|
element.title = 'Classic White T-Shirt'
element.subtitle = '100% Soft and Luxurious Cotton'
element.quantity = 2
element.price = 50
element.currency = 'USD'
element.image_url = 'http://petersapparel.parseapp.com/img/whiteshirt.png'
end
template.build_element do |element|
element.title = 'Classic Gray T-Shirt'
element.subtitle = '100% Soft and Luxurious Cotton'
element.quantity = 1
element.price = 25
element.currency = 'USD'
element.image_url = 'http://petersapparel.parseapp.com/img/grayshirt.png'
end
template.build_address do |address|
address.street_1 = "1 Hacker Way"
address.street_2 = ""
address.city = "Menlo Park"
address.postal_code = "94025"
address.state = "CA"
address.country = "US"
end
template.build_summary do |summary|
summary.subtotal = 75.00
summary.shipping_cost = 4.95
summary.total_tax = 6.19
summary.total_cost = 56.14
end
template.build_adjustment do |adjustment|
adjustment.name = "New Customer Discount"
adjustment.amount = 20
end
template.build_adjustment do |adjustment|
adjustment.name = "$10 Off Coupon"
adjustment.amount = 10
end
end
end
Sending quick replies
delivery = MessageQuickly::Api::Messages.create(recipient) do |message|
message.text = "Pick a color:"
message.build_quick_reply do |quick_reply|
quick_reply.title = 'Green'
quick_reply.payload = 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_GREEN'
end
message.build_quick_reply do |quick_reply|
quick_reply.title = 'Red'
quick_reply.payload = 'DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_RED'
end
end
Plugins
This is optional, and only necessary if you want to add the 'Send to Messenger' or 'Message Us' buttons to your app, shown here:
Firstly, add the javascript require to your manifest file:
//= require message_quickly
Then, in your view templates (presumably slim), add:
= send_to_messenger
= message_us
You can also customize them as such:
= send_to_messenger(size: 'large')
= message_us(size: 'xlarge', color: 'white')
For size, supported values include standard
, large
and xlarge
, while color supports blue
and white
only.
Development & Contributing
Set up your .env
file like so:
FACEBOOK_MESSENGER_VERIFICATION_TOKEN=my_voice_is_my_password_verify_me
FACEBOOK_MESSENGER_PAGE_ACCESS_TOKEN=<generate this on the developer portal>
FACEBOOK_MESSENGER_PAGE_ID=<your facebook page id>
FACEBOOK_MESSENGER_USER_ID=<your own facebook profile id>
FACEBOOK_MESSENGER_USER_FIRST_NAME=<your own facebook profile's first name>
FACEBOOK_MESSENGER_USER_LAST_NAME=<your own facebook profile's last name>
FACEBOOK_APP_ID=<your facebook app id>
You will need your own Facebook profile id if you are to run the specs. Run them now with:
rake
Things on the roadmap include:
- simplify callback names
- catch FacebookApiException errors, can't generate one in the wild yet
- support for customer matching (US-based page required), done but not tested yet
- support for more complex welcome messages
- use webmock to disallow remote requests in specs
Credits
This gem was created by Jaryl Sim. See MIT-LICENSE for details.