Notes from deploying a chat management app:
User Interacts via: FB Page (FB Messenger), LINE, App
User Cannot Interact via: Instagram (no API access to messages)
Two Architecture Options
Architecture: FB Messenger Bot, LINE Bot, AWS API Gateway, AWS Lambda, AWS DynamoDB, Twilio Conversations API, Twilio Programmable Chat API
I got well down the road with this implementation, and will share function code later but decided to stick with adding to an existing Rails API deployed on Elastic Beanstalk to speed up development. I think long term the API Gateway/Lambda approach is the way to go for affordable scaling. Starting small with an existing app allowed me to move quickly and finish the initial prototype in a couple of days.
Alternative Architecture (ended up moving forward with this for now): FB Messenger Bot, LINE Bot, Rails API deployed on AWS Elastic Beanstalk, AWS RDS for persisting User info, Twilio Conversations API, Twilio Programmable Chat API
Steps from 0 to Deployment
- Create a Programmable Chat Service
- Create Programmable Chat User
- Create Programmable Chat Channel
- Create Programmable Chat Member from existing Chat User (user has many member identities)
- Add Member to Channel
- Handling Conversations Part 1: BOTS
- LINE Bot
- Create LINE Bot
- Configure webhooks
- WhatsApp Bot (Skipped)
- FB Messenger Bot
- Create FB MESSENGER Bot
- Configure webhooks
- A Note on Instagram from a frustrated developer (you’re screwed)
- FB Creator Studio might give programmatic access but I doubt it.
- LINE Bot
- Handling Conversations part 2: SMS and Connections
- Configure SMS to receive messages
- Connecting to Ongoing Conversation
- ADMIN Management of Many Conversations, Hopping in and out of Channels, Closing Conversations, Inviting Users to Delegate Conversations
- Cleanup: Archiving Conversations to s3
1. Creating a Chat Service
1 require 'twilio-ruby'
2
3 class TwilioApi
4
5 def initialize
6 account_sid = ENV['twilio_account_id']
7 auth_token = ENV['twilio_auth_token']
8 @client = Twilio::REST::Client.new(account_sid, auth_token)
9 end
10
11 def create_chat_service(name)
12 service = @client.chat.services.create(
13 friendly_name: name
14 )
15 return service
16 end
I created a Twilio API wrapper using the ruby-twilio gem, initialized it using environment variables from my Twilio Account, and just followed the instructions to create a chat service.
The returned object has the unique id I need, the service’s SID, which I save on the Account
object. An Account
will have many Users
(members of the org managing conversations) and Clients
(potentially anonymous clients who might or might not authenticate or place orders)
The Account
now has a canonical Twilio Chat Service for their Account, all Users and Clients of this Account will now be created against this Chat Service.
2. Creating a Chat User
28 def create_chat_user(chat_service_id, client_guid, client_username)
29 #attributes = {}
30 #
31 #username should be email but unauthenticated users
32 #could have anonymous identifiers like Big Red Dog and then
33 #become associated with an email or phone number later
34 #
35 #user.friendly_name = ""
36 user = @client.chat.services(chat_service_id)
37 .users
38 .create(identity: client_guid, friendly_name: client_username)
39 return user
40 end
When a Client
comes to the site and starts interacting with Chat, we will create and persist a Client
object. A guid
is automatically generated on an after_create
hook and that is used for the identity. It’s important to use this guid to create the identity and not the generated anonymous username, because the guid will not change even if we learn more about the user like phone or email, while the username will change if the Client opts to de-anonymize themselves.
Your other option is to require an email or phone number prior to starting chat but this might drive down engagement. And the only way to ensure you’re not getting a fake email just to start the chat (exmaple@example.com) is to send a challenge token, this is way too many steps for customer support or cold leads to go through just to chat.
Main Takeaway: The identity cannot change so use something that will not change to create it.