October 22, 2014

The days of leather bound photo albums are all but gone. Now, people house their prized photos on hard drives, in iPhoto and online. Collage.com makes it easy for anyone to turn those photos into wallpaper, posters and other gifts in a simple web app.

A majority of the photos you publish to social networks are stored on your camera – which is almost always your phone. Collage.com wanted to give their users a direct and secure way to upload photos from their phone to their Collage.com account, without having to open an app or go to their computer. Using Twilio MMS, uploading a photo is as easy as sending a text.

“From customer feedback we know how difficult it can be for users – especially non-techincal ones – to organize and upload photos to yet another service,” said Craig Schroeder, Software Developer at Collage.com “We have seen a very positive response from those that use MMS to upload photos. We have fewer support requests from users that choose this method because they are so familiar with how to send picture messages.”

To get their photos from their phone to their account, all Collage.com users have to do is send a photo to Collage.com’s Twilio number and include a unique code that Collage.com provides. That’s it. From then on out, users can just send pictures to that same Twilio number to upload them to Collage.com.

Users have already uploaded over 41,000 images in the 2 months since Collage.com launched their MMS feature. While Craig admits the numbers aren’t astronomical, the feedback is something they’re taking seriously. “This medium opens up opportunities to interact with our users unlike anything else we have in place,” says Craig.

From Phone To Print: Collage.com Gives Their Users A Direct Way To Make Beautiful Photo Gifts via Twilio MMS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


If you read my post showing how to send SMS messages using Go you know I’ve been spending 2014 learning Go and having tons of fun doing it. My most recent project has been using Go to make and receive phone calls using Twilio. One great thing about working on this is that it required me to learn how to build a basic Go webserver. In this post I’ll show you what I’ve learned and before you know it you’ll be making and receiving phone calls from your Go apps too.

Our Tools

  • Go running on your local machine
  • A Twilio Account – Sign up for free!
  • Ngrok to expose your localhost to Twilio

A Basic Web Server

When a user makes a phone call to your Twilio phone number we ask your server for some basic instructions of what to do with that phone call. In order to do this with Go we need to set up a basic web server. Fortunately Go’s net/http library makes this really easy.

Fire up your favorite text editor and create a new file called main.go. We’ll start it off by declaring our package and importing the net/http package:

package main

import (
  "net/http"
)

Now we’ll write the code that listens for a request to a certain route and responds with some plain text:

func main() {
  http.HandleFunc("/twiml", twiml)
  http.ListenAndServe(":3000", nil)
}

func twiml(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Hello World!"))
}

We create a new function called main. Our main function will be called when our app runs. Inside this function we call http.HandleFunc. http.HandleFunc takes two arguments – the route you want to listen for and the name of the function. If you’re wondering why I’m using the word twiml here, don’t worry it’ll make sense soon. Next we call http.ListenAndServe to start up our server. We’re passing :3000 to listen on port 3000.

Next, we have our twiml function that we said we would use to respond to requests to /twiml. In this case, we’re using the http.ResponseWriter to print out the text “Hello World!”. Let’s run our app to make sure this code works:

go run main.go

Now browse to localhost:3000/twiml and you should see “Hello World!” in your browser.

Speaking Twilio’s Language

Now that we have our basic web server in place we can start building a response that Twilio can understand. This is where TwiML comes in. TwiML is our own subset of XML that lets you provide some basic instructions for Twilio to take when a phone call or message comes in. Let’s update our code to respond to requests to /twiml with TwiML instead of plaintext.

First we need to create a new struct we’ll use to define our TwiML. We can do this right after our imports in main.go. If you haven’t used the backtick character in a long time you can find it on your keyboard next to the number 1:

type TwiML struct {
  XMLName xml.Name `xml:"Response"`

  Say    string `xml:",omitempty"`
}

TwiML contains many different verbs, but in this example we’ll be using the verb <Say>. <Say> let’s you use text-to-speech to say something to the user on your call. Inside our struct we define a string called Say. Go has some awesome tools for converting structs to XML that we’ll be taking advantage of. In our struct we define our XMLName – this will be the root tag it uses when our struct is converted to XML. We also use the xml attribute omitempty on our Say property to make sure we’re not passing along any unneeded tags in the future. In order to take advantage of the XML encoding, we need to add the encoding/xml package to our imports:

import (
  "encoding/xml"
  "net/http"
)

Now we can update our twiml function we wrote earlier to respond with XML:

func twiml(w http.ResponseWriter, r *http.Request) {
  twiml := TwiML{Say: "Hello World!"}
  x, err := xml.Marshal(twiml)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  w.Header().Set("Content-Type", "application/xml")
  w.Write(x)
}

First we create a new TwiML struct with a Say value of “Hello World!”. Then we call xml.Marshal and pass it our struct. This will attempt to convert our struct to XML. If there’s an error with this conversion we’ll send an http.Error. Otherwise, we want to set our Content-Type header to application/xml so that Twilio knows we’re responding with XML. Finally, we’ll actually write the xml content that we generated.

Fire up your app again:

go run main.go

Browse to localhost:3000/twiml and instead of plaintext you should now see the XML response we want to give to Twilio.

For Twilio to access this URL, we need it to be exposed to the outside world. One of the best tools to make this happen is called ngrok. If you haven’t worked with ngrok before let my good friends Kevin Whinnery and Bo Jackson show you how. Make sure you register for a free account so you can use the incredibly helpful subdomain flag. Once you have ngrok setup run it with the following command:

ngrok -subdomain=asubdomainofyourchoice 3000

Now hop into your Twilio account and set up a new number. Configure the voice request URL for this number to your publicly accessible Go URL from ngrok that’s serving your TwiML:

Give that number a call and listen to the beautiful robot voice say ‘hello world’.

Making a Call Using Twilio

Now that we can receive a call let’s use the Twilio REST API to make a phone call. We need to write code that makes a POST request to the Calls resource. We’ll be using a few packages to make this happen, let’s start off by adding them to our imports at the beginning of the file:

import (
  "encoding/xml"
  "net/http"
  "net/url"
  "fmt"
  "strings"
  "io/ioutil"
  "encoding/json"
)

Now we can create a new function called call where our code that makes the POST request will live. We’ll start off with some default variables:

func call(w http.ResponseWriter, r *http.Request) {
  // Let's set some initial default variables
  accountSid := "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  authToken := "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
  urlStr := "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/Calls.json"

}

We’re setting our Twilio accountSid and authToken – you can find these in your Twilio Account Dashboard. Then we build out the urlStr for the Calls resource, this is where we’ll be making our POST request to.

Next let’s set the data we want to use in our request:

// Build out the data for our message
v := url.Values{}
v.Set("To","+155555555555")
v.Set("From","+15555551234")
v.Set("Url","[CHANGE_TO_YOUR_NGROK_URL]/twiml")
rb := *strings.NewReader(v.Encode())

We’ll be passing 3 pieces of information:

  • To – the phone number you want to make the call to.
  • From – The phone number you want to call from. The Twilio number you set up earlier.
  • Url – A URL that returns TwiML instructing Twilio what to do once this call connects. We’ll use the same ngrok TwiML url we used for our outgoing call.

Finally, let’s use Go’s http.Client to make a request:

// Create Client
client := &http.Client{}
req, _ := http.NewRequest("POST", urlStr, &rb)
req.SetBasicAuth(accountSid, authToken)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

// make request
resp, _ := client.Do(req)
if( resp.StatusCode >= 200 && resp.StatusCode < 300 ) {
  var data map[string]interface{}
  bodyBytes, _ := ioutil.ReadAll(resp.Body)
  err := json.Unmarshal(bodyBytes, &data)
  if( err == nil ) {
    fmt.Println(data["sid"])
  }
} else {
  fmt.Println(resp.Status);
  w.Write([]byte("Go Royals!"))
}

We create a new request with a method of POST, our urlStr as the destination and the data we set earlier. We set our authentication and make sure to set our headers correctly. Once we make our request we confirm we got a 200 and if we do parse the response body using json.Unmarshal.

We’re all set to make a call to someone and play an mp3. Let’s add a new route to our web server that we’ll hit to trigger our call:

func main() {
  http.HandleFunc("/twiml", foo)
  http.HandleFunc("/call", call);
  http.ListenAndServe(":3000", nil)
}

Now browse to localhost:3000/call and wait for your phone to ring. When we triggered this request right now we hear our robotic voice again. Let’s update our code to switch the TwiML to use the <Play> verb to play an mp3. First we need to add a new Play property to our TwiML struct:

type TwiML struct {
 XMLName xml.Name `xml:"Response"`

 Say    string `xml:",omitempty"`
 Play   string `xml:",omitempty"`
}

Now that we have our Play property, we can change our twiml function to use it instead of Say:

func twiml(w http.ResponseWriter, r *http.Request) {
 twiml := TwiML{Play: "http://demo.rickyrobinett.com/huh.mp3"}

 x, err := xml.MarshalIndent(twiml, "", "  ")
 if err != nil {
   http.Error(w, err.Error(), http.StatusInternalServerError)
   return
 }
 w.Header().Set("Content-Type", "application/xml")
 w.Write(x)
}

Now browse to localhost:3000/call again. If you didn’t change out the mp3 file in my sample then you should get a glorious message from 1987. Having issues? Take a look at the final code here.

Conclusion

Now that you have the ability to make and receive phone calls from Go what will you build? Maybe something simple like a wakeup call. Or something complex like an IVR or call center. Whatever you build, I’d love to see it. You can find me hanging on twitter or hit me up on e-mail.

Making and Receiving Phone Calls With Golang

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Omnichannel RetailingHave you ever gone to a store to make a purchase and then hopped on your smartphone while in the store to make sure you were getting the best deal? Have you ever found a better deal online from a different retailer and then changed your mind about your planned in-store purchase? This kind of behavior, known as showrooming, is happening more and more often with the rise of smartphones, tablets, and the popularity of ecommerce and online shopping. It plays a major role in omnichannel retailing.

To give you a better idea of what omnichannel retailing is I’ve included the Wikipedia definition below:

Omnichannel Retailing is the evolution of multi-channel retailing, but is concentrated more on a seamless approach to the consumer experience through all available shopping channels, i.e. mobile internet devices, computers, brick-and-mortar, television, radio, direct mail, catalogue and so on.

What does omnichannel retailing mean for marketers? It means that the line between online and offline purchasing has been erased, and marketing needs to reach your target audience everywhere they are looking. Since shoppers are making decisions about in-store purchases on their smartphones, it’s easy for shoppers to change their minds about where they will complete their purchase, causing retailers to lose sales to the competition. Consider these stats:

  • 88% of shoppers research online and purchase in-store
  • 73% browse products in stores before buying online
  • 32% of shoppers have changed their mind about a purchase after researching via mobile while in a store

(Sources: Accenture 2014, Tradedoubler 2014)

Since purchasing decisions are no longer made strictly in one place, it’s now vital for marketers to build a mobile-optimized marketing strategy concentrated on converting omnichannel shoppers.

Omnichannel Sales Means Mobile Marketing Optimization

Getting omnichannel shoppers to convert with your business means having a serious strategy for mobile optimization. This means your website, your display and search ad campaigns, email marketing, and more all need to be optimized for users on smartphone and tablet devices.

  • 60% of the time that Americans spend with online retail occurs on mobile devices (source: comScore, 2014)
  • Mobile shoppers convert 160% more often on sites optimized for smartphones (source: NetElixir, 2014)
  • Average order value from smartphones on mobile-optimized sites is 102% of the average order for desktop sites (source: NetElixir, 2014)

Consider this: people already in a physical store looking to make a purchase would prefer to get what they are looking for in that moment, rather than waiting to order online and have the product shipped to them. However, if this customer sees a better deal online from another retailer, they most likely will not pay more for the same product. There are ways to combat this kind of mobile showrooming:

  • Offer price matching to speed up the sale process and encourage in-store conversion
  • Offer promotions and incentives for making a purchase in-store (receive 10% off your next visit, free 2-year warranty, etc.)
  • Implement an iBeacon strategy to offer coupons or other incentives to buy for people currently shopping in your store
  • Run a display campaign with in-store purchase offers for the products your customers search most

Win More Sales With an Omnichannel Strategy Focused on Smartphone Users

Winning sales from omnichannel shopping means more than optimizing for mobile, it means making it easy for customers to make their purchase fast, or get in touch with you immediately if they have questions. Since these shoppers are often on their smartphones, making it easy for them to call is the easiest and most obvious form of fast customer service.

  • 61% believe it’s important that businesses give them a phone number to call
  • 33% would be less likely to use and refer brands that don’t
  • 52% of those that couldn’t speak to a real person say it has impacted their decision to buy

Making it easy to connect with your business via phone can be accomplished in a few different ways. For example, if someone searches for your store in Chicago and you have locations across the country, make sure the searcher sees your store location nearest to them and a phone number with a local area code. You can also use click-to-call links you make it easy for customers to call your business from their smartphone, while increasing your chances of closing the sale. A recent study by Google showed that people who make mobile searches are 39% more likely to call a business and 51% more likely to make a purchase. That means smartphone leads have immediacy in mind. When people are making purchasing decisions on their phone and have a question, they need an immediate answer. That’s why having phone numbers displayed prominently throughout the online checkout process is important – so people have immediate access to someone who can answer their questions, and help them complete their purchase.

To learn more about omnichannel retail and what it means for your business download the free on-demand webinar, “Smartphones & Omnichannel Retail: 7 Tips to Optimize Sales in a Mobile World.

The post Smartphones Erase the Line Between Online and Offline Purchasing for Omnichannel Retail appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 21, 2014

Toronto-based startup Unified Computer Intelligence last week launched Ubi, a new smart home device that lets users speak voice commands to do things like turn up the heat or open the blinds. The Ubi, which uses the latest in voice recognition, speech triggering, natural language understanding, and speech synthesis, is meant as an easy way […]

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


We’re having a baby!

Sometime in the next four weeks, my wife is going to go into labor. We’ll wait at home for as long as possible, then hop in the car and head to the hospital. At that point begins one of my comparatively few responsibilities for Team Baugues over the next couple days: updating close friends and family of what’s going on.

Of course, after our baby is born we’ll announce on Facebook and Twitter, and I’m sure an email or two will go out. But there are a couple dozen people who are going to want more than an “all done” update on the day after. They’ll want to know when we’re headed to the hospital, how Rachel’s doing along the way, and they’ll want to know that “FIRST MIDDLE Baugues was born at X:XX weighing Y pounds and Z ounces” long before I even think about updating Facebook.

Text messaging seems tailor made for times like these. Unfortunately, texting gets messy when it involves a group of people. I’m simply not going to maintain twenty message threads while my wife’s giving birth. At the same time, I don’t want to include everyone on a single mass-text, blowing up twenty peoples’ phones with the “Congratulations!” of nineteen others.

Broadcast Texts with Twilio

To solve my message “delivery” problems, I’m building a group messaging app using Twilio, Ruby and Sinatra that will let me send one-to-many messages when I make an announcement, and a one-to-one message when my friends text back. And now that Twilio supports MMS, I can send pictures.

Now, I’m building this app to make my life easier on baby day (and if you’d like to see an even more tricked out version of this concept, check out Jarod Reyes’ baby notifier repo. Also, that picture you see up there, that’s Jarod’s son.) That said, text broadcasting has tons more uses than this: emergency management, teachers communicating with students, or talking trash with your fantasy football league to name a few.

In this tutorial, you’re going to build an app to broadcast text messages using Sinatra, Google Docs, and Twilio. This app will:

  • Retrieve contact names and numbers from a Google Spreadsheet
  • Forward a message from your phone to all your contacts
  • Forward a message from one of your contacts to your phone

Here’s what you’ll need to get started:

The rest of this post will walk you through how to write this code line by line. If you’d like to jump to the finished product, check out my Text Message Broadcast GitHub repo. Also, at the bottom of this post you’ll find a Deploy to Heroku button that will get your own broadcast app live in minutes.

Retrieve contacts from a Google Spreadsheet

You could hard code your friends and family’s phone numbers, but that means re-deploying every time you want to add an aunt to the list. Who has time for that when there’s a baby on the way?

A while back I was inspired by this tweet by Patrick McKenzie, a longtime friend of Twilio who recently welcomed his own daughter into the world (Congrats Patrick!):

Screen Shot 2014-10-20 at 11.15.59 PM

Perfect!

Open Google Drive and create a new spreadsheet with two columns named ‘number’ and ‘name’ (it’s important that you give your columns these names and in this order — you’ll see why soon). Punch in a couple numbers to play with — when I was building my app, I used my cell phone and my wife’s cell phone. No point in spamming my friends during development.

Click File -> Publish to Web and you’ll see a link to a publicly accessible version of your document. Unfortunately the document at the other end of this link is not in JSON, but I found this article on How to Use Google Spreadsheet as a JSON backend that tells us how to fix that that.

In the middle of that link (and in the url in the navbar of your browser) is an ID for your spreadsheet: spreadsheet-id You’re going to need that ID in a few minutes. First, open a terminal window and create a new directory for this project. In that directory create new file called broadcast.rb:

mkdir text-broadcast
cd text-broadcast
touch broadcast.rb

Open broadcast.rb and:

  • require the libraries needed to open a uri and parse json
  • define a constant for your spreadsheet ID
  • create a method to return the url of the spreadsheet data in JSON format

require 'json'
require 'open-uri'

SPREADSHEET_ID = '1Uwn2bBpCFNvC4P71gqXFEJuFF-XXXXXXXXXXX-iffg'

def spreadsheet_url
  "https://spreadsheets.google.com/feeds/list/#{SPREADSHEET_ID}/od6/public/values?alt=json"
end

Twilio expects ten digit phone numbers sans punctuation and spaces, prefixed with with a valid country code ( “+1” for the US). Let’s create a method that will sanitize “dirty” numbers so that you can have a little more wiggle room with how you enter them into your spreadsheet. Add this method to bottom of your code:

def sanitize(number)
  "+1" + number.gsub(/$1|\+|\s|\(|\)|\-|\./, '')
end

Next, create two methods to:

  • open the spreadsheet and parse the JSON data
  • iterate through each spreadsheet entry
  • extract the values for each number and name
  • return the pairs as a hash

def data_from_spreadsheet
  file = open(spreadsheet_url).read
  JSON.parse(file)
end

def contacts_from_spreadsheet
  contacts = {}
  data_from_spreadsheet['feed']['entry'].each do |entry|
    name = entry['gsx$name']['$t']
    number = entry['gsx$number']['$t']
    contacts[sanitize(number)] = name
  end
  contacts
end

When run, contacts_from_spreadsheets returns a hash in the format of:

{
  '13178675309' => 'Dad', 
  '13175392342' => 'Mom'
}

For the sake of verbosity, create two simple methods to:

  • return an array of all of our contacts’ phone numbers
  • look up a contact’s name given their phone number

def contacts_numbers
  contacts_from_spreadsheet.keys
end

def contact_name(number)
  contacts_from_spreadsheet[number]
end

And that’s it for Google! If you want to give this a go, load this file in irb and try running each of the methods:

irb
load './broadcast.rb'
puts contacts_from_spreadsheet
puts contacts_numbers
puts contact_name(contacts_numbers.first)

You’ve got an easy-to-maintain phonebook in the form of a Google Spreadsheet. Now let’s do something with those numbers.

Broadcast text messages using Sinatra and Twilio

One thing that’s surprised me since starting at Twilio is how useful Sinatra can be for building Twilio apps. I’ve always been more of a Rails guy, but it turns out that with Sinatra + Twilio you can build some pretty powerful apps in a single file.

To get started, create a Gemfile. It’s a simple app, so you won’t need much:

# Gemfile
source 'https://rubygems.org'
ruby '2.1.2'
gem 'rack'
gem 'sinatra'
gem 'twilio-ruby'

Then install your gems from a terminal:

bundle install

Add two more requires to your broadcast.rb, then add a new constant for your cellphone number: 

require 'sinatra'
require 'twilio-ruby'

MY_NUMBER = '+1312XXXXXXX'

When your Twilio number receives a text, Twilio makes an HTTP request to your server. In the parameters of that request you can find details about the message in the same way that you would find data from from a form submission. Just as a web browser makes an HTTP request and expects an HTTP response in the form of HTML, Twilio expects a response in a form of Twilio-flavored XML that we call TwiML. For example, the generic TwiML to send a single message looks like this:

<Response>
  <Message to='+13128675309' from='+1TWILIONUM'>
    <Body>Look at our new baby!!!</Body>
    <Media>http://imgur.com/cutebabypic.png</Media>
  </Message>
</Response>

If you want to send multiple messages then you simply add more message blocks inside the response tag. If there’s no picture, you omit the <media> tag.

With that roadmap in mind, create a method that will:

  • handle Twilio’s POST request
  • extract the message details
  • call yet-to-be-defined methods to generate instructions on where to forward the messages
  • return those instructions to Twilio as an XML response

post '/message' do
  from = params['From']
  body = params['Body']
  media_url = params['MediaUrl0']

  if from == MY_NUMBER
    twiml = send_to_contacts(body, media_url)
  else
    twiml = send_to_me(from, body, media_url)
  end

  content_type 'text/xml'
  twiml
end

Now let’s create your send_to_contacts method which will:

  • accept a message body and (optional) media_url as arguments
  • iterate through your contacts’ numbers and…
  • … send a message to each number with the appropriate message body and media_url (unless it’s nil)
  • return the text of the generated TwiML response

Thanks to the Twilio Ruby gem, you won’t have to write TwiML by hand.

def send_to_contacts(body, media_url = nil)
  response = Twilio::TwiML::Response.new do |r|
    contacts_numbers.each do |num|
      r.Message to: num do |msg|
        msg.Body body
        msg.Media media_url unless media_url.nil?
      end
    end
  end
  response.text
end

Onto the second use case: a friend texts your Twilio number and you want to forward that message to your cell phone and your cell phone only. Now, when that message shows up on your phone it’s going to be from your Twilio number, so you’ll want to prepend the message body with the sender’s info.

def send_to_me(from, body, media_url = nil)
  name = contact_name(from)
  body = "#{name} (#{from}):\n#{body}"
  response = Twilio::TwiML::Response.new do |r|
    r.Message to: MY_NUMBER do |msg|
      msg.Body body
      msg.Media media_url unless media_url.nil?
    end
  end
  response.text
end

And that’s it for the Ruby code! Open a terminal and fire up your Sinatra server:

ruby broadcast.rb

Make it Live

There are only two more steps needed to make your broadcast system operational from your development machine:

  • make your Sinatra server accessible to the public Internet
  • tell Twilio where to find it

There are a number of ways to do the former, but my favorite is to use ngrok. If you haven’t used ngrok before, this article from Kevin Whinnery will show you how to set it up in less than five minutes. I highly recommend registering for a free ngrok account so that you can take advantage of the subdomain flag which will prevent you from needing to update your webhook settings in Twilio everytime you restart ngrok. Once you’ve installed ngrok, start it up and point it at Sinatra’s default port, 4567:

ngrok -subdomain=example 4567

Finally, tell Twilio where to find your webserver when it gets an incoming text:

webhook

That’s it! Save your settings and send a text to your Twilio number. The numbers you defined in your spreadsheet should get a copy of the message. Reply from a number that’s not MY_NUMBER and you should get that message only on your cellphone. Now try it with a picture.

Deploy to Heroku

In order for this app to be useful when your computer’s offline, you’re going to have to get it off of your development machine and into the cloud. The easiest way to deploy the stock version of this app (found at my GitHub repo) is to click this button:

Deploy

(Props to Heroku for that little piece of magic.)

Once you’ve done that, you’ll need set environment variables for MY_NUMBER and SPREADSHEET_ID:

  • go to the dashboard for your Heroku app
  • click Settings at the top right of the page
  • click Reveal Config Vars
  • click Edit
  • Add MY_NUMBER and your cellphone in the format of: +1XXXYYYZZZZ
  • Add SPREADSHEET_ID

heroku-config

Then, in your Twilio dashbaord, point the messaging URL for your Twilio number to http://yourherokuapp.herokuapp.com/messaging. 

Onward

Congrats! You now can blast out text and picture messages to friends and family while maintaining your contacts as easily as updating a spreadsheet. I hope it’s as useful for you as I imagine it will be for me in a few weeks.

If you run into any problems along the way, have a cool story to share about how you’ve used this app or if you have any tips on how to survive the first few weeks of parenthood, hit me up at gb@twilio.com or @greggyb. Fair warning though, I may be a bit preoccupied starting around mid-November.

 


Cover photo by: Claire SuniBaby by: Jarod Reyes.

“It’s a Boy!” How to Broadcast Text Messages using Ruby, Google Spreadsheets and MMS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


CMOsEvery year IBM releases the key findings from their Global C-suite Study and everyone scrambles to dig through it to find that one piece of information that might change their entire marketing strategy. To save you some time, we’ve picked five key takeaways from the study of 4,183 top executives from more than 20 industries so you can learn how the big dogs are earning the loyalty of “digitally enfranchised customers and citizens.” Let us know in the comments if you’re a CMO—or another C-suite exec—who has some thoughts about what it means to be a CMO in this changing world of marketing.

1. CMOs influence CEOs more than almost any other exec.

CEOs are increasingly calling on CMOs for strategic input, according to the study. In fact, CMOs are “second only to the CFO in terms of the influence he or she exerts on the CEO.” 63% of the CMOs surveyed are involved in business strategy development, so this means it’s more important than ever for CMOs to have access to flawless data. After all, if the CEO is going to lean on the head of marketing for advice when major decisions are being made, then the data those decisions are made from needs to be solid. In this new era of the CMO’s role, all marketing successes, without exception, need to be able to be attributable. Marketers have access to all kinds of tools to help with this—clickstream reporting, advanced call tracking abilities, Google Analytics integrations—and this section of the study reinforced the fact that CMOs, more than ever, need to be on top of all the ways to prevent making important decisions on bad data.

2. Very few CMOs have implemented key components of a digital strategy.

This is an unfortunate point to be made, but one that is important for CMOs to hear: when it comes to implementing advanced analytics to capture customer insight across all touchpoints, a whopping 88% of CMOs only “somewhat” or “to a limited extent” explored those avenues. What’s more, only 16% of CMOs have integrated customer touchpoints across physical and digital channels to what they consider “a large extent,” and only 20% are using social media to a large extent. With the changing paths of how customers are making purchasing decisions and the multiple avenues they have in gathering information about companies they want to do business with, many businesses are scrambling with how to keep up with them, and marketing organizations are struggling to find ways to engage with their customers in ways that are meaningful to the customer, as well as finding ways to measure that engagement.

“To succeed in the digital era, you have to be totally in sync with the behavior and preferences of your customers in a fast-changing landscape,” a quote from the study says. “You have to be quick and adaptable.” It’s true. If marketers want to integrate customer touchpoints across physical and digital channels, then they have to get used to the idea that those touchpoints might exist in mediums they’re not comfortable with: social media, or a phone call. Many CMOs are uneasy with these one-to-one engagements, but with research showing that mobile search will drive over 73 billion phone calls by 2018, CMOs need to bite the bullet and meet their customers where they are, wherever that might be.

3. There’s a huge gap between aspiration and action.

Above, we noted the findings that CMOs are lagging in their use of digital and digitally integrated technologies. But it’s important to note that these same CMOs have aspirations to use the technology they’re behind in utilizing. 94% of CMOs plan to use mobile applications more extensively in the future, compared to 80% in 2011, and 89% plan to focus on customer relationship management more extensively, compared to 81% in 2011. Interest in advanced analytics is up too, with 94% of CMOs expressing a desire to increase usage, compared to just 66% in 2011. CMOs have their eye on the ball, but can they catch it fast enough? Can you?

4. CMOs fall into three distinct profiles.

Despite similarity in the challenges they face, the report found that CMOs fall into three distinct profiles: the Digital Pacesetter, the Social Strategist, and the Traditionalist. The Traditionalist are struggling with data, new channels/devices, have yet to integrate physical and digital sales and service channels, seldom engages on social media, etc. The Social Strategist has gone a little farther, recognizing social media’s potential and building infrastructure to operate in the social arena. But, like Traditionalists, haven’t begun to fully take advantage of the data and analytics social media offers. Finally, the Digital Pacesetters are much farther down the road and are prepared for the data explosion and are actively putting the resources required to operate as a fully integrated physical-digital enterprise in place. They regularly use advanced analytics to generate insights from customer data. Guess who’s outperforming who?

5. Winning CMOs know the value of data.

This ties all the way back to #1. With CEOs relying more heavily on CMOs for decision-making, successful CMOs know the increasingly value of good data, and according to the study, 66% of those abovementioned Digital Pacesetters who are outperforming other CMOs are integrating data from all sources to better understand customers: they understand that data and creating an optimal customer experience are not exclusive. This means embracing all channels of engagement with them: social media, mobile experience, phone calls, and more. The pressure is on CMOs, and who comes out on top will say everything about how willing they are to embrace a rapidly shifting marketing world.

The post 5 Crucial Things CMOs Need to Know from the IBM CMO Study appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 20, 2014

You can check how many stars your favorite restaurant has on Yelp easily. But stars might not tell the whole story of that restaurant’s health inspection scores, history, and violations. Accela Inc worked with the City of Evanston to make the city’s restaurant health scores publicly available and programmable via SMS.

seth

Relaying resturant data via Twilio SMS was the easy part for Accela Developer Evangelist Seth Axthelm (pictured right).  “It’s so easy and so inexpensive and so powerful,” says Seth. Seth only wrote 50 lines of code, to give any Evanston resident  the ability to text the name and location of a restaurant to a Twilio powered phone number to see its health score and history.

Writing code was a breeze, but standardizing the data that powers the app was an uphill battle.

Data and The Network Effect

To better understand how a bit of siloed data like health inspection records traveled from a government database to an open data platform to Yelp’s API, to Twilio’s API and finally a text message, let’s take a look at the fax machine.

Remember the fax machine? The first fax machine didn’t have much value. When the second, third, and fourth etc. fax machines were up and running, faxing (in the 90s) became a viable and valuable form of communication. That one hunky piece of hardware made it easy to share information because it was so widespread and uniform. Every fax machine could communicate with every other fax machine using the same set of standards. This is called the network effect.

The same principle applies when it comes to data. If you standardize the way you classify and record data, it’s easy for others to use. When it comes to digesting data there is no more literal use case than Accela’s.


 

Making Data Digestible

Accela worked with Code for America to fly the flag of Open Data, pushing for high quality data standards that could unlock a wealth of governmental data that is either siloed or proprietary. Standardizing that data, and making it open source, can open doors for developers to make a city, its businesses and history more accessible.

Using the platform CivicData.com, which allows any resident to add government data to the site that can then be accessed programmatically via an API, Seth made the first iteration of his health score app.

Using the data standardization model called “LIVES (Local Inspector Value-Entry System)”, you can publish health score data in a particular format than Yelp can consume, and use it in its algorithm to make accessible to all users.

With accessible data in hand, Seth chose the most widely accessible platform to distribute it – SMS. Seth saw SMS as an easily adopted and instant way for anyone to access health standards.

Seth hopes to bring the app to other cities, along with the same set of data standardization. He’s also working on a similar feature that will give any city resident information on building construction, permit requests and construction permits.

Learn more about Accela here.

Data and Dining: Accela Unlocks Government Data Using Yelp API, Open Data and Twilio SMS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


businesswoman socialWe recently learned all about message delivery in the age of anti-advertising while attending a Business Marketing Association of Chicago Marketing Innovators luncheon where Neal Campbell, EVP and CMO, and Lauren McCadney, Digital Engagement and Social Media Director, from CDW spoke to us about what it’s going to take for marketers to connect with our customers. In this new era, customers actively tune out our messaging and have a number of resources at their fingertips that they are using to proactively conduct research before ever contacting businesses directly.

Here are three key points we took away on what marketers need to embrace in order to break through the anti-advertising barrier.

 

 

 Meet Me On The Web: The New Buyer Journey

Campbell and McCadney led off by discussing how the buyer journey has been completely revolutionized alongside growing Internet penetration. A typical buyer journey now looks like the following:

  • Search (web)
  • Community (web)
  • Search (web)
  • Reviews (web)
  • Sales: to validate
  • Buy

“People are becoming smarter at the cart,” McCadney states, and with nearly 60% of the buyer’s journey complete before they even reach out to sales, we can see they are spending that time educating themselves before they even contact a company for validation or make a purchase. The majority of these consumers are beginning their search online (in fact, Google reports that smartphones are now the most common starting place for online activities) and will then turn to online peers for help in understanding the pros and cons of the product or service they are researching. All of this action is taken online, prior to engaging with your company.

So how do we stay relevant in a process that is dominated by digital research? McCadney asserts “we need to delve into the customer journey by digitizing their experience with our brands.” Engaging Digital Natives, she continues, requires connecting with them on their platform of choice, and in the right spaces on these platforms, in order to drive greater brand consideration. Marketers working to keep brands in the conversation throughout the buyer’s journey will help drive consistent consideration and return sales to being seen as another research tool, not simply a pit-stop toward the end of their decision.

People Trust People

Campbell and McCadney spoke about how, in order to stay relevant throughout the customer journey, we not only have to meet our customers on the web but also engage with them at a human level – where their trust lies.

Today 90% of people do not trust advertising, yet 92% trust recommendations from people they know. And another 70% trust opinions posted online – from people they may not even know at all! Campbell claims that as marketers, “our task becomes making our people human and making sure they have the tools to be human” in order to build this trust with our customers and engage with them throughout their purchase journey. For many businesses, what is more human that voice? Ensuring we are available to engage in conversation with our customers can be the difference in whether we get their business.

Create Brand Advocates: Customers To Build Customers

The discussion also turned to how we can play off the trust people have with one another. Marketers must engage customers not only where they are online – using search, social media, and communities – but use the relationships they have built to our advantage by letting them do the talking for us. CDW did this very simply by incorporating reviews – both positive and negative – onto their website, bringing in the feedback their customers have and sharing it in a controlled space. Amplifying their voice will create advocates for your business that prospects already trust. By doing this marketers can continue to break down the anti-advertising barrier, bringing humanness to business and another way to build trust with our customers.

At the end of the day, Campbell and McCadney’s message was about being human. In a growing anti-advertising culture, we as marketers are driven to engage with our customers on a social, human level to grow an environment of trust and acceptance. We first need to meet them where they are (on the web) and then engage in a genuine way (by being human).

And we want to ask, what is more human than voice? With smartphone ownership growing (there will be an estimated 220 million by 2018) and increasingly being used as a starting point for online activities, it is that much easier for people who are researching to use their smartphone as an actual phone. Incorporating click-to-call functionality in our mobile marketing and tracking inbound calls will help us stay relevant in the buyer’s journey and bring us one step closer to voice conversation – and being human.

The post Understanding How to Engage a Growing Anti-Advertising Audience appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 17, 2014

data analyticsMarketing has become synonymous with data and analytics. Wait, did I just say that marketing is equivalent to data? Why yes, I did. Marketing is no longer confined to simply branding a product or service, but rather is being used to draw insights that generate greater numbers of high-quality leads and create more personalized customer experiences. And – you guessed it – they are doing this by using data to prove the value of marketing and drive more targeted messaging.

In fact, marketing provides more of a competitive advantage for businesses than ever before. The data now available to us from our marketing efforts, including call analytics, offers more opportunity to optimize ROI, yet we have somehow ended up with more systems and siloed data than we know what to do with. If you’ve ever felt overwhelmed by the thought of big data, or by the number of programs with which your data is collected, integration presents the ability to combine this information in fewer places. Linking this data enables us to get the full picture of marketing effectiveness across channels, devices, and conversion methods to see which activities have the greatest impact – online, offline, and mobile.

Still skeptical that marketing isn’t about the numbers? Here are a few stats to reinforce how marketers are embracing big data and data analytics and trying to determine best practices to integrate this vast amount of information.

Marketers Recognize the Value of Data and Integration

As technology grows and we have more access to data, many marketers understand that they have a lot of information at their disposal and need to find a way to combine the disjointed sources from which it comes. More data equals more feedback on our marketing, and with that the opportunity to optimize what may or may not be working.

1. 85% believe big data will dramatically change the way we do business in the future. (Accenture)

2. Majority (37%) indicated that big data will have the largest impact on customer relationships in the next five years. (Accenture)

3. 62% say creating a single, central customer marketing database that houses customer experience information is a priority for their organization. (Forbes)

4. 79% agree that companies that do not embrace big data will lose their competitive position and may face extinction. (Accenture)

5. The vast majority (9 in 10) believe that connecting the disparate tools in their company’s marketing technology stack would improve their ability to innovate, personalize consumer interactions, send timely messages, boost loyalty, evaluate campaigns, and increase return on marketing investments. (Signal)

Yet They Are Confused on How to Integrate

Real-time personalization of our marketing stems from the ability to have integrated data platforms, yet marketers acknowledge their tools are currently being underutilized and they still face obstacles to implementation.

6. Senior executives polled in North America said their companies were using an average of 36 different data-gathering systems and vendors. (Forbes)

7. 38% say too many systems and 37% say siloed data are a top technology challenge to developing a single customer view. (Forbes)

8. 51% of marketers say they have yet to integrate marketing technologies beyond the most basic level. (Signal)

9. 1 in 2 marketers report that fragmented technologies impede their ability to create a consistent experience for consumers across the web, mobile, and other channels. (Signal)

10. Only 4% feel well prepared to move forward with cross-channel marketing based on their technology stack capabilities. (Signal)

And Don’t Forget to Close the Loop on Your Reporting

Marketers looking for the full picture of their marketing efforts, and want close the loop on their reporting, understand the need to analyze data from all lead sources, including the ones sales professionals deem most valuable: phone calls. According to BIA/Kelsey, 61% of sales managers consider inbound phone calls to be excellent leads, more than any other type.

And as the proliferation of smartphones grows, so too are the number of inbound calls to businesses (BIA/Kelsey). Tracking calls and utilizing voice-based marketing automation tools offer marketers a competitive advantage with a growing and valuable lead source. And it’s easier than ever to integrate this data into existing CRM, web analytics, marketing automation, and bid management systems, as well as other applications.

Interested in garnering more data from your marketing? Check out our eBook, “The Definitive Guide to Voice-Based Marketing Automation” to learn how VBMA tools offer advanced call analytics and the opportunity to integrate call data with existing applications.

The post 10 Stats That Underscore the Growing Value of Integrated Data Analytics appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 16, 2014

The following is a guest post by DigitalOcean

At DigitalOcean, we communicate with our customers and staff in numerous ways. One of the most important ways we communicate is via text message. Twilio, our provider of text message services, offers an intutitive API that allowed us to quickly integrate text messaging and then to expand our usage of it throughout our applications.

We first heard of Twilio through a project one of our interviewees built (PS – he got the job!). The engineer prototyped the Twilio SMS powered Two Factor Authentication system that we still use today in our control panel. Since we launched two factor authentication over a year ago, tens of thousands of our customers have enabled TFA to add an additional layer of security during the authentication process. Using Twilio’s developer accounts to test and prototype, we worked out the user flow and quickly shipped an important security feature to doing business online.

Beyond security, SMS plays an important role in internal communication at DigitalOcean. When we have time-sensitive alerts and notifications to send, our employees look to text as a necessary communication channel. By alerting support staff of critical tickets via SMS, we ensure that our customers get the timely response they need – in some cases reducing response times from hours to minutes.

As a Twilio partner, Twilio’s service helped our customer base in several ways. Not only has the platform effortlessly handled our SMS volume doubling over the last year, but delivery speed and geography (location of the recipient) have been minimal problems.

DigitalOcean’s focus on simplifying hosting for developers. The developer’s first experience signing up and running through features is a critical step in our business. Waiting for a text message would be a major user experience let down. Twilio helps us ensure a great first experience with SMS verification.

As a company with customers on every continent but Antarctica, we have to work with partners who can provide the same level of service to customers globally. Since a few issues are inevitable, we’ve built tools on top of Twilio’s API to surface details of deliverability problems for our support team that allows them to work with customers to diagnosis and fix issues.

Looking to the future, SMS will become an increasingly important channel. We’re looking at ways to use SMS in identity verification and to prevent fraudulent credit card usage. With a combination of a readily programmable interface (text) and a relatively hard to get attribute (a phone number), SMS offers another tool to use in combating identity theft and ensuring that our cloud stays a safe place to do business.

Does this sound like fun? We’re building and shipping code daily at DigitalOcean. Apply at [DigitalOcean Careers].

DigitalOcean Communicates Clearly With Twilio SMS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Last month I showed you how to send daily SMS reminders with Firebase, Node.js and Twilio. A week later we launched MMS on long codes in US and Canada and I thought what better way to take advantage of this than to update my app to include a picture in my daily message. What kind of picture would I want to get sent every day? A random gif from Giphy of course! Let’s get to work updating the SMS code to do this. If you haven’t already worked through the previous post, go back and knock it out. Don’t worry, I’ve got plenty of gifs to watch while you’re working.

#BeRoyal

Want to see this app in action? Well I hope you’re as excited about the Kansas City Royals as I am because I built an app that will text you a random Royals gif every afternoon. Want to subscribe? Text the word ‘subscribe’ to (816) 844-6184.

beroyalnotifications.gif

Sending a Gif On Signup

If someone is subscribing to have a gif sent to them everyday, obviously we should send them a great gif to congratulate them when they sign up. To send an MMS using TwiML we want to nest <Body> and <Media> nouns inside our original <Message> verb. If you remember, we’re using the Twilio node helper library to generate our TwiML. With our node library we can nest verbs or nouns by passing a callback function to the function that creates our initial verb. For the sake of clarity, I’ll show the entire /message route and highlight the lines we’re changing to accomplish this:

app.post('/message', function (req, res) {
  var resp = new twilio.TwimlResponse();
  if( req.body.Body.trim().toLowerCase() === 'subscribe' ) {
    var fromNum = req.body.From;
    if(numbers.indexOf(fromNum) !== -1) {
      resp.message('You already subscribed!');
    } else {
      resp.message(function() {
        this.body('Thank you, you are now subscribed. Reply "STOP" to stop receiving updates.')
            .media('http://media.giphy.com/media/zl170rmVMCpEY/giphy.gif');
      });
      usersRef.push(fromNum);
    }
  } else {
    resp.message('Welcome to Daily Updates. Text "Subscribe" receive updates.');
  }
  res.writeHead(200, {
    'Content-Type':'text/xml'
  });
  res.end(resp.toString());
});

 

The body will contain the text we want to reply with. Media contains a url to the image we want to reply with. Be sure to pick a great gif from Giphy to send. I went with this one. Text ‘subscribe’ to your Twilio number and get a virtual high five!

MOAR GIFS!

There’s one major problem with our app right now – there aren’t enough gifs! Fortunately for us we can tap into the Giphy API to access more gifs than we would ever need. To interact with Giphy from our app we’ll be using the giphy-wrapper node library. Let’s install it using npm:

npm install giphy-wrapper

Now let’s instantiate the library at the top of our app.js file:

var giphy = require('giphy-wrapper')('YOUR_API_KEY');

The giphy-wrapper lets us easily search Giphy for gifs with a certain tag. Let’s add the code that pulls gifs tagged puppy to our app. Replace the code that was in our textJob callback from the last post with this code:

var textJob = new cronJob( '0 18 * * *', function(){
  giphy.search('puppy', 100, 0, function (err, data) {
    if (err) {
      console.log(err);
      return;
    }

    var gifs = data.data;
    var gif = gifs[Math.floor(Math.random()*gifs.length)];
    console.log(gif);
  });
});

We’re using the giphy-wrapper to pull 100 puppy gifs from Giphy. If there’s an error, we’ll log it to the console. Otherwise, we’ll pull a random gif from our response and log it to the console. Run this code and see it in action. Don’t forget to update the time on your textJob to a time in the near future so you’re not stuck waiting hours to test your code.

Someone Put a Picture in My Message

Now that we’re pulling a random gif from Giphy, let’s add the code that sends that to everyone who is subscribed to get updates. Right after we pull our random gif add the following code:

giphy.search('puppy', 100, 0, function (err, data) {
    if (err) {
      console.log(err);
      return;
    }

    var gifs = data.data;
    var gif = gifs[Math.floor(Math.random()*gifs.length)];
    for( var i = 0; i < numbers.length; i++ ) {
      client.sendMessage( 
        { 
          to:numbers[i], 
          from:'+15555555555', 
          body:'PUPPY!!!!', 
          mediaUrl: gif.images.downsized.url
        }, function( err, data ) {
           console.log( data.body );
        }
      );
    }
  });

This code is almost identical to the code we previously used to send SMS messages. We use the sendMessage function provided by the Twilio node library to send our message. The one difference is the we’re also passing a mediaUrl as an argument when we call sendMessage. This mediaUrl is a publicly accessible url to the gif we want to send. Giphy gives us many versions of the gif to retrieve but we’ll be using the downsized image.

Run your app, subscribe and see it in action.

Let There Be Gifs!

You can now send daily animated gifs. Who will be the first to build an animated gif Chuck Norris app? I can’t wait. It’s been almost 1 full month since we opened up MMS. Have you already built a killer MMS hack? I’d love to see it! Questions/Comments? Hit me up on twitter or drop me an e-mail.

Send Daily Animated Gifs Using Firebase, Giphy, Node.js and Twilio MMS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Dynamic RemarketingIn June 2013 Google launched dynamic remarketing for retail advertising clients with a Google Merchant Center account. Just recently, on October 1st, they launched the dynamic remarketing feature for all remaining advertising verticals including hotels, flights, real estate, finance, education, and more, according to the AdWords blog.

What is Dynamic Remarketing?

Dynamic remarketing enables advertisers to instantly create customized ads that follow users around after they visited a particular page on your website. Dynamic ads often include the content, product, etc. that the user was viewing before leaving your site. These ads can also include related products or services that a user might be interested based on the content they viewed.

Dynamic display ads can be created automatically using templates provided by Google. The ads are tailored based on segments you set up and on the products visitors viewed on your website. Audience targeting is easy to set up using the Similar Audiences tool (available to all AdWords clients).

The Impact of Dynamic Remarketing for Advertisers

Google’s introduction of dynamic remarketing across all verticals means the opportunity for advertisers to show even more targeted, highly relevant content to their target audience. Dynamic ads have been shown to decrease shopping cart abandonment and increase ROI. Google made implementing dynamic remarketing easy: a site-wide remarketing tag can be implemented quickly to start remarketing campaigns.

Results: According to Google, advertisers implementing dynamic advertising are already seeing positive results: 2x increase in conversion rates and 60% reduction in CPA on average.

Increase Conversion Rates on Dynamic Remarketing with Call Tracking

It’s easy to increase your dynamic remarketing conversion rates by including call tracking phone numbers in your ads. Users who see your ad can call the tracking phone number in your ad to get connected to your team immediately. Inbound calls convert to revenue 10x more often than web form fills, so whether the user is seeing an ad on a desktop device or a mobile device, making it easy for them to call will help improve your bottom line. Since mobile devices account for more than 55% of internet usage (CNN Money) it’s important to optimize for mobile, and make it easy for mobile users to connect with your business.

Remarketing is a great way to target customers who are already familiar with your product/service but have not yet converted. To learn more about remarketing tools and best practices, check out this blog on B2B retargeting.

The post Google Introduces Dynamic Remarketing Across All Verticals appeared first on Ifbyphone.

        

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 15, 2014

As you know, a number of news sources, corporations and the OpenSSL team reported yesterday 14 October 2014 that version 3 of Secure Sockets Layer (SSLv3) is vulnerable at the protocol level.

We are urging all customers to disable SSLv3 on hosts interacting with the Twilio service as soon as possible and upgrade to use Transport Layer Service (TLS).

Owing to many clients and servers connecting to Twilio that currently do not support TLS, we have not immediately turned off SSLv3, but are providing a mitigation path as defined below.

This path affects customer applications in two ways:

  1. On the REST API requests they make for outbound calls and messages
  2. On the webhooks made by Twilio to their applications for inbound calls and messages.  Twilio is making the following adjustments to the security of these services to mitigate this vulnerability.

REST API – Outbound Calls and Messages

For customers using an official Twilio helper library and those consuming the REST API through a different HTTP client, we encourage them to mitigate this vulnerability by disabling SSLv3 on their hosts as soon as possible.

For customers negotiating with Twilio over SSLv3, we plan on discontinuing this service on 22 October 2014 at 9am PDT / 1600 UTC.  Customers with clients that only support SSLv3 are encouraged to upgrade to TLS as soon as possible.

Webhooks – Inbound Calls and Messages

For customers only supporting SSLv3 for inbound HTTP requests from Twilio, we plan on discontinuing this service on 22 October 2014 at 9am PDT / 1600 UTC.  Customers with applications that only support SSLv3 are encouraged to upgrade to TLS as soon as possible, as SSLv3 will be unavailable on that date.

Disabling SSLv3 For Your Platform

To assist customers disable SSLv3 for your hosts, we have found the following resources to be helpful:

Update: Scott Helme published this excellent step-by-step guide on mitigating this vulnerability on multiple platforms, web servers and clients.

Thank you for your prompt attention to this security disclosure.  As always, if you have any questions about this notification or the security of your Twilio account, we encourage you to reply to this email or email help@twilio.com for additional assistance.

Security Notification for SSLv3 POODLE Vulnerability

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Proper nutrition is a topic that is near and dear to my heart. I struggled at one point in my life with making the right food choices and over time the weight piled on. After learning a lot about nutrition, I feel like I have a good handle on making choices in the grocery store. This isn’t always easy though and it is really difficult when traveling.

As an evangelist I travel a lot, so often I come home to an empty fridge. Sometimes I know that I will be leaving in a few days for another trip so I don’t want to do a full fridge restock. A couple quick and easy meals is all I’m after. There be dragons! Convenience food is some of the worst stuff on the planet for you but there are healthier options even in this realm of on-the-go eating. With a couple of quick photos of barcodes and an MMS message, you can get the nutrition decision you need without having to read labels and compare calories, protein, carb and fat totals.

Hot Pockets or Amy's?

Try it yourself! Grab some food items and snap some clear, up close pictures of their barcodes and send them to:

United States: (267) 433-2613

Canada: (450) 954-1629

Recipe (get it?!)

How It Works

Workflow Part 1

Workflow Part 2

Our user will have a few ways to work with our barcode to nutrition info service. The first option is sending in a single barcode. In this case, we will return nutrition information for the single product. Another option is to send in multiple barcodes with an optional keyword to indicate how to process the information. If no keyword is specified we will total up the nutrition information for all of the products send in. This will help the user tell the nutrition details for a meal composed of these items. If the user sends in the ‘compare’ keyword, we will send back a “winner” based on the calories, protein, carbs and fat totals for the given items. This will help the user choose a particular item based on their nutrition goals.

There is a chance that some barcodes will not be recognizable. There is also a chance that some products will not be available in the Nutritionix database. I chose the Zxing.NET barcode reader because it was free, easy to work with and worked on most barcodes I sent to it. I chose Nutritionix because they have a well-populated database of items with the ability to query via barcode. There are many other nutrition databases available which have more items in them. Feel free to explore the options out there.

The full project is available if you want to follow along: Github

Setting Up the Project

Start by creating a new ASP.NET Web Application project from the Empty template with MVC references:

ASP.NET Project

Add a new controller to the project called BarcodeNutrition. Delete the default Index() method since we won’t need it in our application.

Now we need to install some NuGet packages for the libraries we will be using. First we’ll install the Twilio.Mvc package (commands shown for Package Manager Console):

Install-Package Twilio.Mvc

Next, we’ll install the ZXing.NET package:

Install-Package ZXing.Net

Finally, install the Nutritionix package:

Install-Package Nutritionix

Add the following using statements to the top of BarcodeNutritionController.cs:

using System.Drawing;
using System.Net.Http;
using System.Text;

using Twilio;
using Twilio.TwiML;
using Twilio.TwiML.Mvc;
using Nutritionix;
using ZXing;

We also need to add an action method to handle incoming messages from Twilio. This will be the entry point to our service:

public async Task<ActionResult> Inbound(int numMedia, string body)
{
    var response = new TwilioResponse();

    // Trim incoming text to remove whitespace
    body = body.Trim();

    // Code to generate nutrition info result...
    return new TwiMLResult(response);	
}

All the pieces are in place for us to begin writing our barcode to nutrition info service. There are a lot of moving parts in this hack so you’re probably going to want to be able to test things as you build them. When Twilio receives an incoming message at your phone number it will need to make an HTTP request to our Inbound action method. If you want to test locally you will need to expose your localhost to the outside world. I recommend using ngrok for this. You can use this tutorial to help get you set up with ngrok on your Windows machine. Once you have that up and running, configure the Messaging URL for your Twilio number in the numbers portal to point at your local server’s /BarcodeNutrition/Inbound endpoint:

Number config

With this set up you will be able to send barcodes to your Twilio number during the development process so I’d encourage you to set breakpoints and write tests as you follow along.

Reading Barcodes From the Incoming Images

We first check to make sure the user sent in at least one image. If they didn’t we need to let them know to try again with some barcodes:

// No images sent in
if (numMedia == 0)
{
   response.Message("You didn't send any barcodes! Please send in well-focused and zoomed in barcodes with the word 'total' to get total nutrition values or 'compare' to get a comparison of the items.");
   return new TwiMLResult(response);
}

This will generate TwiML to be returned to Twilio. TwiML is XML that tells Twilio how to handle incoming messages and calls. In this case we are returning TwiML that tells Twilio to send an SMS message back to the user with the text specified. Here is the TwiML generated by the code above:

<Response>
   <Message>You didn't send any barcodes! Please send in well-focused and zoomed in barcodes with the word 'total' to get total nutrition values or 'compare' to get a comparison of the items.</Message>
</Response>

Read this document to learn more about TwiML.

With that out of the way we can get down to the business of decoding the barcode images. Add this code to the Inbound method:

// Decode the barcodes
string[] eanCodes = await DecodeBarcodes(numMedia);

if (eanCodes == null)
{
   // There was an error with one of the barcodes. Bail so user can try again.
   response.Message("One of your barcodes was not recognized. Please try cropping your image or taking the picture again closer to the barcode.");
   return new TwiMLResult(response);
}

This code relies on a DecodeBarcodes method that we will add now:

private async Task<string[]> DecodeBarcodes(int numberOfImages)
{
   // Build a List<Bitmap> from incoming images
   var images = new List<Bitmap>(numberOfImages);

   // Build an array of EAN codes from reading the barcodes
   var eanCodes = new string[numberOfImages];

   var httpClient = new HttpClient();
   var reader = new BarcodeReader();

   for (int i = 0; i < numberOfImages; i++)
   {
       Bitmap bitmap;

       using (var stream = await httpClient.GetStreamAsync(Request["MediaUrl" + i]))
       {
           using (bitmap = (Bitmap)Bitmap.FromStream(stream))
           {
               var result = reader.Decode(bitmap);

               if (result == null)
               {
                   // Couldn't read this barcode, we'll return null to indicate we should bail...
                   return null;
               }

               eanCodes[i] = result.Text;
           }
       }
   }

   return eanCodes;
}

For each barcode image that is sent in there will be a corresponding media URL. We use this URL to populate a Bitmap object which is required by the ZXing.NET barcode reader. If the barcode is able to be decoded we add the result string to an array of EAN codes. If any of the barcodes are unreadable we return null from the method. A failed barcode reading means we can’t perform a total or a comparison so we want to give the user a chance to try again.

At this point we have a list of EAN codes that can be used to query the Nutritionix database for nutritional info.

Before moving on, try these barcodes to make sure the reader is working properly:

Hot Pockets

Cheerios

Mmm, Hot Pockets and Cheerios…that’s a meal fit for a king if I’ve ever seen one.

Fetching Nutrition Info From Nutritionix

The Nutritionix API is queryable using the barcode numbers available on our food and drink items. The NutritionixClient object in the NuGet package we added earlier makes it really easy to work with this information. Add the following class level variables to the top of the BarcodeNutritionController making sure to replace the placeholders with your credentials:

private string _nutritionixId = "[Your Nutritionix Application ID]";
private string _nutritionixKey = "[Your Nutritionix Application Key]";

Next we’ll set up a list for food items we successfully query and another for barcodes that are not found in the Nutritionix database:

List<Item> foodItems = new List<Item>();
List<string> skippedBarcodes = new List<string>();

Now we’ll add the method that will populate these lists by querying the Nutritionix API:

private void LookupNutritionInfo(string[] eanCodes, ref List<Item> foodItems, ref List<string> skippedBarcodes)
{
   // Initialize the NutritionixClient
   var nutritionix = new NutritionixClient();
   nutritionix.Initialize(_nutritionixId, _nutritionixKey);

   // Create lists for food items and any barcodes that aren't in the database
   foodItems = new List<Item>(eanCodes.Length);
   skippedBarcodes = new List<string>();

   // Loop through each barcode
   foreach (var barcode in eanCodes)
   {
       Item food = null;

       try
       {
           // Fetch nutrition info by EAN code
           food = nutritionix.RetrieveItemByUPC(barcode);
       }
       catch
       {
           // Invalid barcode format results in a 404. We'll add it to the skipped barcodes list.
           skippedBarcodes.Add(barcode);
           return;
       }

       if (food != null)
       {
           foodItems.Add(food);
       }
       else
       {
           // One of the food items is not available in Nutritionix.
           skippedBarcodes.Add(barcode);
       }
   }
}

 

Note the try/catch block in the middle of the method. This will handle scenarios where the barcode format is not recognized since NutritionixClient will throw an HttpException for the resulting 404 error in this case.

Now we can call the nutrition lookup from our action method passing in the two lists as reference parameters:

LookupNutritionInfo(eanCodes, ref foodItems, ref skippedBarcodes);

If we had to skip any barcodes because they weren’t in the Nutritionix database, we’ll let the user know to try again without these barcodes:

if (skippedBarcodes.Count > 0)
{
   // Let's tell the users that we couldn't find their item(s)...
   var builder = new StringBuilder();

   builder.Append("Sorry but we couldn't find one or more of your items. Please try again without the following EANs which were not found in the Nutritionix database: ");

   foreach (var barcode in skippedBarcodes)
   {
       builder.Append(barcode + " ");
   }

   response.Message(builder.ToString());
   return new TwiMLResult(response);
}

At this point we have all of the food items populated and can process the results based on what the user requested. In the case where we only have one barcode, we’ll return nutrition details for just that item:

private string GetSingleItemNutrition(Item foodItem)
{
   return String.Format(
           "Here are the details for {0} {1}: {2} calories, {3}g protein, {4}g total carbohydrates, {5}g total fat.",
           foodItem.BrandName,
           foodItem.Name,
           foodItem.NutritionFact_Calories,
           foodItem.NutritionFact_Protein,
           foodItem.NutritionFact_TotalCarbohydrate,
           foodItem.NutritionFact_TotalFat
   );
}

If the user wanted the server to total up the nutrition info either by specifying the ‘total’ keyword or by not specifying a keyword we’ll use the following method:

private static string GetTotalNutrition(List<Item> foodItems, string[] eanCodes)
{
   // Default to returning total nutrition info
   var totalCalories = foodItems.Sum((item) => item.NutritionFact_Calories).Value;
   var totalProtein = foodItems.Sum((item) => item.NutritionFact_Protein).Value;
   var totalCarbs = foodItems.Sum((item) => item.NutritionFact_TotalCarbohydrate).Value;
   var totalFat = foodItems.Sum((item) => item.NutritionFact_TotalFat).Value;

   return string.Format("Here are the totals for the items you requested: {0} calories, {1}g protein, {2}g carbohydrates and {3}g total fat.", totalCalories, totalProtein, totalCarbs, totalFat);
}

The last option for processing the results is the ‘compare’ function:

private string CompareNutrition(List<Item> foodItems, string[] eanCodes)
{
   var lowestCalories = foodItems.Aggregate(
                               (item1, item2) => item1.NutritionFact_Calories < item2.NutritionFact_Calories ? item1 : item2
                           );

   var highestProtein = foodItems.Aggregate(
                               (item1, item2) => item1.NutritionFact_Protein > item2.NutritionFact_Protein ? item1 : item2
                           );

   var lowestCarbs = foodItems.Aggregate(
                               (item1, item2) => item1.NutritionFact_TotalCarbohydrate < item2.NutritionFact_TotalCarbohydrate ? item1 : item2
                           );

   var lowestFat = foodItems.Aggregate(
                               (item1, item2) => item1.NutritionFact_TotalFat < item2.NutritionFact_TotalFat ? item1 : item2
                           );

   return string.Format(
       "Lowest calories: {0} {1} (barcode: {2}) with {3} calories. Highest protein: {4} {5} (barcode: {6}) with {7}g of protein. Lowest total carbs: {8} {9} (barcode: {10}) with {11}g carbs. Lowest total fat: {12} {13} (barcode: {14}) with {15}g fat.",
       lowestCalories.BrandName,
       lowestCalories.Name,
       eanCodes[foodItems.IndexOf(lowestCalories)],
       lowestCalories.NutritionFact_Calories,
       highestProtein.BrandName,
       highestProtein.Name,
       eanCodes[foodItems.IndexOf(highestProtein)],
       highestProtein.NutritionFact_Protein,
       lowestCarbs.BrandName,
       lowestCarbs.Name,
       eanCodes[foodItems.IndexOf(lowestCarbs)],
       lowestCarbs.NutritionFact_TotalCarbohydrate,
       lowestFat.BrandName,
       lowestFat.Name,
       eanCodes[foodItems.IndexOf(lowestFat)],
       lowestFat.NutritionFact_TotalFat
   );
}

This method tries to help the user pick the best choice depending on some common nutrition goals – low calorie, high protein, low carb and low fat. It’s not a perfect way to pick the right food but it’ll do when you’re stuck at a gas station trying to decide between cheese puffs and a granola bar.

Now we just need to add a method to decide which calculation to use:

private string GetNutritionInfoResponse(int numMedia, string keyword, List<Item> foodItems, string[] eanCodes)
{
   string responseString = "";

   // Depending on number of items and the keyword in the Body, run some nutrition calculations
   if (numMedia == 1)
   {
       // Single item, just return details for that item.
       responseString = GetSingleItemNutrition(foodItems[0]);
   }
   else if (keyword == String.Empty)
   {
       // Default to totals
       responseString = GetTotalNutrition(foodItems, eanCodes);
   }
   else if (String.Equals(keyword, "total", StringComparison.OrdinalIgnoreCase))
   {
       // User explicitly requested total nutrition info
       responseString = GetTotalNutrition(foodItems, eanCodes);
   }
   else if (String.Equals(keyword, "compare", StringComparison.OrdinalIgnoreCase))
   {
       // User requested item comparison
       responseString = CompareNutrition(foodItems, eanCodes);
   }
   else
   {
       // Invalid keyword
       responseString = String.Format("You sent in '{0}' which is not a valid keyword. Please send in well-focused and zoomed in barcodes with the word 'total' to get total nutrition values or 'compare' to get a comparison of the items.", keyword);
   }

   return responseString;
}

We’ll call this from our Inbound method and return the resulting response string as TwiML to Twilio. The user will get a text message with their requested nutrition information. Armed with this info, hopefully they will make the right choice in the grocery aisle.

Now that the app is completely built, give it a try by sending a couple of barcodes to your new Twilio MMS enabled phone number. Make sure to try out the “compare” feature!

Next Steps

I hope you find this tool as helpful as I did when I wrote it. It definitely served me well this week as I came back from Xamarin Evolve only to have to head off to Connect.js in a few days. With a quick couple of picture messages I was able to grab a few healthy meals for the week!

You don’t have to stop with what I built here though. Here’s some next steps:

  • Render a nutrition label and return it via MMS
  • Send the nutrition data to MyFitnessPal, Fitbit, etc.
  • Make better choices and live a healthier life!

I hope you’re excited to build lots of cool things with MMS using C#. I’m stoked to see what you create so please share them with me on Twitter @brentschooley or through email at brent@twilio.com.

Pick the Right Meal Using C#, ASP.NET and Nutritionix

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Call-CenterAirports always provide numerous sources of frustration. Something always goes wrong and there is always something that gets on your nerves. Yet, we suck it up, grit our teeth, and continue on because there is no way to avoid it. From the moment you walk into the airport, to the time you exit the airport at your destination, you are stuck in a never-ending series of lines. We all know these struggles, and it’s even more frustrating when it seems that there are a thousand simple ways for the airlines and TSA to expedite the process of commercial flying. Being placed on hold when calling into a business is no different. The excruciating feeling that comes from waiting in line is still present. Giving your business the power to control your call queuing experience can provide a completely different voice for your business. Get your callers out of line and talking to your representatives faster with a virtual call center.

Shorten Your Lines

It’s easy to criticize airport employees when we can all see just about a thousand ways for them to improve their customer service. The airlines and the TSA always employ as few people as possible to keep their costs down. Wouldn’t it speed up the process infinitely with just a few more employees?

Shorten your hold times for without having to increase your staff by implementing a virtual call center. With a virtual call center, you can have your agents answering calls wherever they go. Routing your calls based on your business needs means that when an agent gets a call, that caller is already talking to the right person. This means no more time wasted on rerouting calls. Add an IVR to this, and you can have an automated survey direct the caller to the best possible agent. With IVR you can also provide self-service functionality, freeing up agents for more important inquiries. These features all make it possible for your agents to answer more calls and handle them as efficiently as possible, clearing up your phone lines for more customers.

Change Your On-Hold Experience

The ability to control your call queuing experience lets you make the caller experience a lot less dreary. Having control over the music or promotional messages they hear, the maximum time they will have to spend waiting, and the number of callers in your queue you can make the experience a lot more satisfying for the caller.

Caller Information at Your Fingertips

Have you ever called into a support line and provided information to an automated system, only to have the service representative ask you to identify yourself again? This is always frustrating, but it’s easily prevented. By integrating with CRM and help desk systems like Salesforce and Zendesk, you can provide your agents with a wealth of information about the caller. For new sales leads, every call will get logged into your CRM with information on who they are, where they are calling from, and what marketing source led to the call. For support calls, information on the caller will be instantly available and a new ticket can be created from the call. For any existing contact, their information will be instantly available, and details from the call will be logged automatically.

Skip the Line

TSA has a new offering called Pre-check that allows you to skip the gargantuan security line and expedite your security check. You can do the same thing for your VIP customers with priority call queuing. This will send your most important clients to the front of the line so they can get assistance immediately. You can also provide your callers with the option to request a callback and exit your on-hold queue without losing their place in line. They will be called back automatically when they reach the front of your queue.

Take Your Call Center Out of the Past

Waiting in line is something we all have to do on occasion. During times like traveling or waiting to ride your favorite roller coaster, we accept the line as something we have to deal with. That is not always the case when waiting in line on the phone. Our benchmarking analysis indicates that 15% of callers tend to hang up right around 40 seconds. If you take too long to answer your phones, you may be losing out on business. Ifbyphone’s virtual call center makes it easy to deploy a solution for any size business to cost-effectively manage inbound phone calls. To learn more about improving your customer service with a virtual call center, download our white paper: The Next Generation of Virtual Call Centers: Beyond the Cloud.

The post Getting Your Customers Out of Line With a Virtual Call Center appeared first on Ifbyphone.

        

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


We are halfway through October, but there’s still time to address health literacy, in honor of Health Literacy Month. This dedicated month was established in 1999 by Helen Osborne, M.Ed., OTR/L, a clinician and president of Health Literacy Consulting, and is designed to promote the importance of understandable health information for both organizations and individuals.

As mentioned in our previous blog post, health literacy enables one to make decisions regarding one’s health based on the ability to obtain, process, and understand basic health information. Important for health literacy is the use of Universal Design for Learning (UDL), a set of principles for curriculum development that give all individuals equal opportunities to learn (Source: UDL Center). These principles provide better ways to reach the low literacy population by presenting content in ways other than a large block of text to be read.

A large portion of the month is made up of events to promote health literacy on both a corporate and an individual level. The month promotes aligning with businesses, including large international pharmaceutical corporations, as well as aligning locally with schools and healthcare professionals. Additionally, students and parents are encouraged to put health first and increase health literacy, since good health is crucial for learning.

There are many websites that provide healthcare information in a way that is simple to understand. Some of these websites employ the principles of UDL by making their content available in other formats, including video and audio. Visit the following websites to increase your health knowledge:

The theme of this year’s Health Literacy Month is “Be a Literacy Hero”. Become a hero by taking action and finding ways to improve health communications. If you already have a literacy hero, nominate an individual or organization here.

Get Your Free Guide:
Everything You Always Wanted to Know about Speech-Enabling Websites

Download Your Free Guide

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 14, 2014

SpareFoot knows how to multitask. This past April, they served a record number of users looking for storage facilities, matching them with the right price and vendor. In the midst of this season, SpareFoot was planning the next iteration of their call center at the same time. With the help of one of our Twilio Solution Partners, NewVoiceMedia, SpareFoot was able to design, prototype and ship their new call center to handle their future growth before their current busy season was over.

Founded in 2009, SpareFoot offers their users an easy and intuitive way to find the right storage space, in whatever zipcode they need it, online and in the comfort of their home. SpareFoot also provides storage facility owners across the country an online marketing resource to drive business to their own storage locations. Over the past few years, SpareFoot has been able to expand their business drastically, and in doing so needed a call center that could expand with their business gracefully.

SpareFoot didn’t want to get stuck with a rigid call center in their next busy season. Being unable to handle high per-second call volume, or change up agent call flows easily, would be disastrous for their business. To ensure they had the flexibility they need to be successful in the future, SpareFoot switched their call center vendor to NewVoiceMedia.

sparefoot-office

Keeping Things Flexible

SpareFoot’s business is elastic, it grows and shrinks with the seasonality of storage rental business. Joshua Lipton, VP of Technology at SpareFoot wanted a call center that mirrored their business: ready for rapid expansion in the busy times, and easy to manage and staff in slower times. Paying a fixed rate for an on-premise solution didn’t make sense for SpareFoot’s business. Josh had ideas for Twilio powered features he wanted to build on-top of their call center to make serving customers easier for SpareFoot’s agents. But, it wasn’t easy with his previous call center vendor.

Josh was familiar with Twilio and knew the Twilio could provide the features he wanted to add to his call center. But, his previous vendor made it difficult to integrate solutions like call queuing, tracking, and conferencing easily. This didn’t match with the product roadmap Josh built to support SpareFoot’s booming business.

Build or Buy

He then had to make the choice: build or buy. Josh wanted the flexibility of a contact center he built himself, but didn’t want to sacrifice the developer hours it would take to maintain it. To get the flexibility he wanted, and guarantee his developers time could be put to good use, Josh called NewVoiceMedia.

NewVoiceMedia flew into Austin, Texas, SpareFoot’s headquarters, for two days of discussion, building and prototyping. Josh expected that they’d have a skeleton of the new call center he wanted drafted by the end of the two days. He needed NewVoiceMedia to do some heavy lifting: replicating call flows, building call logic, integrating Salesforce information, and more. Within hours of arriving at SpareFoot HQ, New Voice Media replicated SpareFoot’s call flow and had test environments up and running. Josh was pleasantly surprised.

“We had fairly complex call flows, and we needed some really cool call routing logic, our complexity is deep,” said Josh “We really thought the hard part was going to be ACE (Amazing Customer Experience team, SpareFoots’ primary support team), but a couple hours later, they had done that as fast as well.”

Building with the ACE team in mind was a critical step. NewVoiceMedia needed to ensure that the ACE team agents have access to the right information about the right customer, so they can cut down on call time and give customers more detailed support. Making sure user information is both secure and easily accessible for agents is a tremendous effort that normally requires multiple teams and iterations. NewVoiceMedia had it figured out in an afternoon.

As a deeply technical company, SpareFoot chose NewVoiceMedia for the efficiency and reliability of their code. Josh remembers watching NewVoiceMedia’s demo of communications through Salesforce, a feature he wanted to ship badly. With Salesforce open on one screen, Josh saw that the instant a call came through, an agent screen pop appeared. The two were completely in sync.

Over the next two days NewVoiceMedia worked with Josh and his team to complete and iterate on the call center SpareFoot is currently running today as they prepare for another busy season. This time, they won’t have to worry about changing call centers.

Learn more about NewVoiceMedia at Dreamforce, catch their session “Achieve a Multi-Channel Contact Center with One Integration” Wednesday, October 15th, 3:00pm at the Cloud Expo (Partner Theater North). NewVoiceMedia will run through the business benefits of integrating NewVoiceMedia’s multi-channel routing solution seamlessly inside your Salesforce environment – so agents can handle inquiries across phone, email, and social without leaving the Salesforce console they know and love. Maximize the customer experience by intelligently routing the right case to the right agent – every time.

SpareFoot Scales For Success With NewVoiceMedia and Twilio

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


2094749782_4f5f003c49_bWhen you are using Twilio to power communications in your business or your software applications, you want to know what is going on all the time, especially if things go wrong. There are plenty of tools in the Twilio cloud to help you dissect these errors and figure out what went wrong. One particularly useful tool is the Twilio App Monitor.

The App Monitor will log every single error that Twilio encounters talking to your application- failing to validate or parse a TwiML document, or not being able to get a response back from a url. If any of these operations (and many others) go wrong, Twilio logs it in the App Monitor for you.

Please don’t make fun of how many mistakes I make

One of my favourite features of the App Monitor is the App Monitor Triggers:

There are three triggers created by default in every account that are fired on the first, tenth and one hundredth error each day. By default these triggers will send an email to you telling you about the error. You can make your own triggers for specific errors or a certain number of errors in a time period. For example: you could make an App Monitor Trigger that fires every single time a 13266 Invalid Country Code error is triggered.

We’re software people and we don’t always want to be told via email that something has gone wrong. We want to be told fast, in a more convenient way, and right now! Especially if we’re deploying some critical code and we want to make sure it works efficiently.

App Monitor Triggers can send an HTTP POST request to a URL of your choice instead of an email. This is a mechanism often referred to as a webhook. The webhook request will contain a bunch of useful information about the error that just occurred as POST data, which you can then extract from the request and manipulate in software as you chose. Maybe you’ll want to log it in a database, or send a hipchat notification to your developers warning them that the world is ending and they need to fix it.

I was recently building an application that used the App Monitor Trigger webhooks, and I realised – what is the best real time communication platform that I can use to alert myself when things go wrong? Why SMS of course and I had heard of this thing called Twilio. I decided to put a Twilio inside my Twilio, so I could Twilio whilst I Twilio’d.

What you’ll learn

Let’s build an SMS alert system that sends us an SMS message when we get App Monitor Error using the App Monitor Trigger webhooks.

In this blog post you will learn to:

  • Set up a new App Monitor Trigger with a configured webhook
  • Use hurl.it to receive mock HTTP requests to your web server with mock error information.
  • Use the Twilio REST API to send an SMS message

The only thing that you will need for this (other than your favourite programming language, we’re going to demonstrate with Python) is a Twilio Trial Account, which you can sign up to for free. It only takes 30 seconds to sign up.

Creating a new Twilio App Monitor trigger with a configured webhook

This part of the tutorial is very easy, we’re just going to go to the Twilio App Monitor in our User Account on twilio.com and click on “Triggers”:

By default, each account is given three App Monitor Triggers but we want to create a new one. Let’s go ahead and click on Create New Trigger on the right:

We’re going to make a trigger that fires whenever a HTTP retrieval error occurs. This is a fairly common error that can occur when developing with Twilio so it makes a good example. In production, I’d recommend setting up App Monitor Triggers for the most likely errors that will happen with you Twilio application. If you’re unsure what these are, check the App Monitor for a list of errors you already have – it’s likely they’ll occur again!

Here we are setting the Friendly Name to HTTP retrieval error, this is a human-readable name that will be useful for your debug team later on, so make sure it is descriptive. The Error Code we’re monitoring is 11200 – HTTP retrieval failure, which occurs when Twilio makes an HTTP request and receives a HTTP 404 status code back. We want the Trigger Value to be 1 (every 1 times, the trigger will fire) and we want to set the Recurring value to Daily.

What does this give us? An App Monitor Trigger that fires on the occurrence of an HTTP retrieval error, the first time it happens, every day.

Now for the little trick, instead of adding an email address into the field below, click on the Trigger a Webhook link on the right to turn this into a programmatic trigger:

We need to add a URL to the new field that appears.

This URL will receive an HTTP POST request when this Trigger is fired, with information on the error. The HTTP Request will send us the following parameters:

You can read more about Twilio App Monitor Triggers on the documentation page.

Finally, we can save the new App Monitor Trigger by clicking on Save.

Receiving the App Monitor Triggers in our application

Now that we have an App Monitor Trigger ready to fire, we need to write some code on our server that will receive the HTTP requests and diagnose them.

In this example I’m going to use Python and Flask (a micro web framework) to build a simple server that receives the request and creates SMS messages from them.

If you do not yet have Flask installed, you can install it with pip using this terminal command:

$ pip install Flask twilio

We’ve also installed the Twilio Python helper library at the same time.

The boilerplate Flask code we need, which will be familiar to all Flask developers, is going to be saved in a file called app.py:

from flask import Flask
app = Flask(__name__)

if __name__ == "__main__":
    app.run(debug=True)

We need to add a URL route on the server for the HTTP requests to go to. In Flask, we can do that pretty easily:

from flask import Flask
app = Flask(__name__)

@app.route('/error_trigger', methods=['POST'])
def error_triggers():
    return 'Hello Twilio!'

if __name__ == "__main__":
    app.run(debug=True)

The new code we’re adding on line 4 registers a new URL route in our Flask app called /error_trigger, just like the configuration we have above in our App Monitor Trigger. We’re also accepting HTTP POST methods on this line with the second parameter.

This route is linked to a function we’ve called error_triggers, which takes no parameters, and just returns a string ‘Hello Twilio’ for now. This is currently useless to us, so let’s actually intercept the request coming in and print something from it:

from flask import Flask, request
app = Flask(__name__)

@app.route('/error_trigger', methods=['POST'])
def error_triggers():
    error_code = request.values.get('ErrorCode', None)
    return 'The error is {0}'.format(error_code)

if __name__ == "__main__":
    app.run(debug=True)

The new code (on lines 6 and 7) replaces the simple Hello Twilio print statement. Instead we are getting a value out of the HTTP request (in this case, ErrorCode) and storing it in a variable. On line 7, we’re returning out the error code.

Using hurl.it to test out our application

We’ve got our application to the point where we probably want to start testing that it works. It is impractical and bad practice to force errors from a Twilio application. Instead, I discovered a great tool for sending HTTP requests called hurl.it, which lets you make HTTP requests, add headers or parameters to them, and change the HTTP methods too. It also displays the responses nicely.

Oh, and it has an awesome vomiting unicorn as a mascot, so why not use it?

Let’s go to hurl.it and configure a simple HTTP POST request, with a single parameter, ErrorCode, and fire it at our webserver:

It’s very simple to set up a request with hurl.it, let’s click Launch Request and check out the response we get:

The HTTP response is successful (we get a 200 OK response) and the body shows us the code we wanted to return based on the value we sent to it.

Nice! We can get our application to talk to us. Let’s change the code to print out a useful statement based on some of the parameters a Twilio App Monitor Trigger might send:

from flask import Flask, request
app = Flask(__name__)

@app.route('/error_trigger', methods=['POST'])
def error_triggers():
    error_code = request.values.get('ErrorCode', None)
    description = request.values.get('Description', None)
    if error_code:
        msg = 'An error on your Twilio app occurred! {0}'.format(description)
        doc_url = ' https://twilio.com/docs/errors/{0}'.format(error_code)
        msg += doc_url

        return msg

if __name__ == "__main__":
    app.run(debug=True)

The new code (on lines 8 to 13) is retrieving the Description and ErrorCode value from the HTTP request and formatting it to make a nice message, including a URL link to the Twilio documentation on that error. Note that the URL won’t work on an “any error” trigger.

Let’s send another hurl.it request to our application and see what the response looks like now. I’ve modified the parameters to simulate a real error, the HTTP retrieval failure error:

and let’s look at the response we get:

Sending SMS with the Twilio REST API

This is now looking good, but we’re not actually sending any SMS messages yet, so let’s add the final bit of code to turn this message into a Twilio SMS and actually make it useful.

from flask import Flask, request
app = Flask(__name__)

from twilio.rest import TwilioRestClient
client = TwilioRestClient('TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN')

@app.route('/error_trigger', methods=['POST'])
def error_triggers():
    error_code = request.values.get('ErrorCode', None)
    description = request.values.get('Description', None)
    if error_code:
        msg = 'An error on your Twilio app occurred! {0}'.format(description)
        doc_url = ' https://twilio.com/docs/errors/{0}'.format(error_code)
        msg += doc_url

        client.messages.create(
            to='YOUR_NUMBER',
            from_='TWILIO_NUMBER',
            body=msg
        )

        return msg

if __name__ == "__main__":
     app.run(debug=True)

There is a lot of new stuff happening here, so let’s step through it all one bit at a time.

On line 4 we are importing the TwilioRestClient, which is a Python helper library for Twilio. On line 5 we instantiate the helper library with our Account Sid and Authentication Token. Our ACCOUNT_SID and AUTH_TOKEN can be found on our Twilio dashboard.

The only other code we’re adding is a few lines starting on line 16, which creates a new SMS message. The parameters given to this function include the to phone number, which is the number you want to send the message to (your phone, if you’re not sure) and the from number, which should be a Twilio number. If you do not have a Twilio number (every trial account has one), you can get a new one in the numbers panel on your account page. Finally, the message we want to send is the same message that we’re printing out.

Now, when we make the same HTTP request, we should also receive an SMS message to the phone number that we entered:

Mathematical!

What’s next?

Now if you deploy this code onto your server, your developer team will always know what is up as soon as a problem occurs.

What have we learned here? We’ve just covered the advanced topic of monitoring application errors in your Twilio Apps, setting up a webhook trigger, and using Twilio SMS through the REST API by building this nice little app.

I think it is good at this point to look at some of the best triggers to monitor in your application. Here are my suggestions:

  • 11200 – HTTP retrieval failure – Great for checking new endpoints, you will want to monitor this as soon as it happens, so set the trigger value to 1.
  • 13226 – Dial: Invalid Country Code – Occasionally users might format a number wrong and this is a good way to check if that is happening. Unless this is essential, I’d set the trigger value quite low, to catch it early.
  • 13520 – Say: Invalid Text – If you’re automatically generating text to speech, this trigger is a must-have. You’ll always get some random gibberish breaking the TTS engine.

Twilio has an extensive list of App Monitor Errors that might occur, so it is worth checking them out. Don’t forget to read the full App Monitor Triggers documentation too.

If you have any questions, feel free to email me at paul@twilio.com or get in touch on Twitter.

Monitor your Twilio applications with SMS alerts using the Twilio App Monitor, Python and webhooks.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


One of the great ironies of the last few years has been the explosion in popularity of the animated GIF. Just as browsers were finally starting to embrace cutting-edge technologies like WebRTC, WebSockets and WebGL, a technology first supported by Netscape 2.0 in 1995 completely took over cultural landscape on internet. You can’t read a sports blog, a tweet or even go to a technology conference without running into the humble animated GIF.

Despite the popularity of animated GIFs, the tools for making them aren’t great. Personally, I wanted something simple that I could use to convert cute videos of my kids on my phone into animated GIFs. Now, there are several tools for converting videos to animated GIFs on your computer. Recently some developers from Yahoo released Gifshot, a tool that converts videos into animated GIFs inside of your browser using open web technologies. But I wanted to build a web service, so I needed to rely on software that was either built-in to or could be easily added to a standard Linux server distro. After some trial and error, I landed on the following combination of technologies:

  • Ubuntu 14.04 on a Digital Ocean VPS
  • Libav – to process the videos and retrieve the frames
  • Imagemagick – to stitch together the animated GIF
  • Node.js – to orchestrate and serve the generated animated GIFs
  • Twilio – to send and receive MMS messages

You can try out a hosted version of the app I built by sending a short video (think Vine, 6 seconds or less) to:

United States: (747) 900-4443

Canada: (778) 655-4263

After being notified that your video has been queued, you should receive an animated GIF version of your video. In this blog post we’ll walk through the process of building this app from scratch by spinning up a Linux VPS, installing the necessary software on it, building a simple Node application to orchestrate the conversion of videos to animated GIFs and wiring it into a Twilio number. This is what you will accomplish when you’re done:

twilio_mms

What You Will Need

Here are the two things you’ll need to get started:

  1. Twilio account with an MMS-enabled phone number
  2. Ubuntu Linux server with Node.js installed

For the purposes of this blog post I’m going to use a Digital Ocean droplet to power this service. If you already have an Ubuntu VPS with Node.js installed you can skip ahead to Step 2.

Step 1: Create a Digital Ocean Droplet

Create a Digital Ocean account and get a free $10 credit with the code twilio10. Once you’re logged in click on the “Create” button to spin-up a new droplet (this is what they call a VPS).

DigitalOcean_Control_Panel

Give your droplet a name and select the smallest plan.

DigitalOcean_Control_Panel2

Scroll down and under the “Select Image” section click on “Applications” and then choose the Node/Ubuntu image. This will spare you from having to manually install Node on your new droplet.

DigitalOcean_Control_Panel3

Finally, click on “Create Droplet”. Once your droplet is up and running the root password will be emailed to you.

Step 2: Install libav and imagemagick

Now it’s time to install the binaries that we’re going to use to process video and create animated GIFs. Open up a terminal program on your local machine and SSH into your droplet. If you haven’t already, please create a non-root user and grant that user sudo privileges. Next, install libav and imagemagick:

sudo apt-get update
sudo apt-get install libav-tools
sudo apt-get install imagemagick

Libav
 is a set of programs for processing video and you’re going to use the program 
avconv
 to pluck frames out of the video you receive from Twilio. Make sure that it’s working on your system as it should by creating an animated GIF from a video.

mkdir tmp
cd tmp
curl -O http://linode.rabasa.com/bouncing.3gp
avconv -i bouncing.3gp -r 8 -vframes 48 -f image2 bouncing-%03d.jpeg

Here you are passing in a video in the 3gp format.  If you’re curious what video formats that avconv supports on your system just run

avconv -formats
.

Here is an explanation of the flags used in the example above:

  • -i : the input file
  • -r : the number of frames per second to grab
  • -vframes : the maximum number of frames to grab
  • -f : the output format

The last parameter to the command tells avconv what to name the output files. The “%03d” is a special mask that avconv will use to number each of the files starting at 1. If all goes well you should end up with 48 (or less) jpeg files in the 

tmp
 directory.

Like libav, 

imagemagick
  is a set of programs for manipulating images. Use the 
convert
 program to stitch the frames together into an animated GIF:

convert -delay 12 -loop 0 bouncing*.jpeg bouncing.gif

There are the flags I’m using:

  • -delay : number of 1/100ths of a second to pause between each frame
  • -loop : causes it to loop over and over

You should now have an animated GIF named bouncing.gif in your directory. Take a look at that GIF in your browser using Node.

Step 3: Create the Node App and Serve Static Files

In your home directory create a new application directory and initialize node:

mkdir apps
mkdir apps/gifit
cd apps/gifit
npm init

When you run

npm init
  the process will ask a series of questions to help set up your Node application and create a
package.json
  file. Give it any name you like and use the default entry path (
index.js
 ). Next, add the node-static module to your app:

npm install node-static --save

This module will make it easy for us to serve the generated GIFs as static files. Now edit

index.js
  and add some code to serve static files:

var http = require('http')
  , static = require('node-static');

// The directory where our animated GIFs will live
var dir = new static.Server('./public');

// Spin up our HTTP server
http.createServer(function(req, res) {
 req.addListener('end', function () {

   dir.serve(req, res);

 }).resume();
}).listen(process.env.PORT || 3000);

console.log('Listening on port ', process.env.PORT || 3000);

In your application’s directory create a subdirectory called 

public
  and copy the animated GIF that you generated earlier into the that new directory. Now start-up your Node server:

mkdir public
cp ../../tmp/bouncing.gif public
node .

Open up a browser and go to the IP address of your VPS at port 3000 and append the name of the generated GIF: 

http://your_ip_or_domain:3000/bouncing.gif

If everything is working you should see this:

2014-10-09 10.56.48

Step 5: Receive an MMS from Twilio

twilio_mms-1

Now that your system can successfully convert videos into animated GIFs, it’s time to add some logic to your Node application to accept video content from Twilio, orchestrate its conversion and return the animated GIF. Add the following modules to your project. I’ll discuss what these modules do as you build out your service.

npm install glob node-uuid request twilio --save

Go ahead and open up

index.js
  and add the following code to the top:

var http = require('http')
  , static = require('node-static')
  , os = require('os')
  , fs = require('fs')
  , glob = require('glob')
  , util = require('util')
  , exec = require('child_process').exec
  , request = require('request')
  , url = require('url')
  , twilio = require('twilio')
  , uuid = require('node-uuid')
  , child;

The url module is built-in to Node and will give you an easy way to get information about each web request to your Node application. You might ask why I’m not using a framework like Express or Hapi to build this application. The answer is that this application handles only two kinds of requests and doesn’t do anything fancy with the inputs or outputs. I felt like this was a good opportunity to keep things close to the metal.

Modify your HTTP server code to parse the incoming request and invoke the  

handleMessage
  function when the path is
/message
 .

// Spin up our HTTP server
http.createServer(function(req, res) {
 req.addListener('end', function () {
   // if the requested path is /message, process the incoming MMS content
   if (url.parse(this.url).pathname === '/message') {
     handleMessage(req, res);
   }
   // else serve static files
   else {
     dir.serve(req, res);
   }
 }).resume();
}).listen(process.env.PORT || 3000);

In the 

handleMessage
 function, you need to determine if the media you’ve been sent is indeed a video. If so, send the user a message that their video has been queued and will be processed shortly. If not, send them a message letting them know that they need to attach a proper video file.

var handleMessage = function(req, res) {
 // Parse the request URL
 var hash = url.parse(req.url, true);
 // This is the phone number of the person who sent the video
 var phone = hash.query['From'];
 // This is the URL of the file being sent
 var mediaUrl = hash.query['MediaUrl0'];
 // This is the content type of that file
 var mediaContentType = hash.query['MediaContentType0'];
 // This is the host the machine serving this Node process 
 var host = req.headers['host']; 

 console.log('Processing MMS: ', mediaUrl, mediaContentType);

 res.writeHead(200, {'Content-type': 'text/xml'});
 var twiml = new twilio.TwimlResponse();
 // if media URL looks like a valid video, send ok back to the user
 if (mediaContentType.indexOf('video') >= 0) { 
   twiml.message('Video queued for processing, hang tight!');
   res.end(twiml.toString());
   processVideo(mediaUrl, host, phone);
 }
 else {
   twiml.message('This is not a video format that we recognize. Try again?');
   res.end(twiml.toString());
 }
}

Now that you have a URL to a video file you can create a function called 

processVideo
 to handle the conversion of this file into an animated GIF.

Step 5: Orchestrate using child_process

twilio_mms-2

At a high level there are a few things that 

processVideo
  needs to do:

  1. Download the video to the local filesystem.
  2. Call 
    avconv
     to convert this video file into frames.
  3. Call 
    convert
      to stitch these frames into an animated GIF.
  4. Send a message to the user with a pointer to this hosted GIF.

Since there will be files created during this process (some of them being temporary and subject to later deletion) you can use the node-uuid module to create a practically unique prefix for these files.

The

os.tmpdir
  function returns the operating system’s temporary directory which should be available for you to create and delete files in. The 
request
  module helps you fetch this URL and save it to the temporary directory with the filename of the generated UUID. When the download is finished its time to kick off the processing of the video.

var processVideo = function(mediaUrl, host, phone) {
 // create a unique UUID for all of our video/gif processing
 var id = uuid.v1();

 // Save the remote movie file to the /tmp fs
 download = request(mediaUrl).pipe(fs.createWriteStream(
   util.format('%s/%s', os.tmpdir(), id)));

 download.on('finish', function() {
   // Once it's saved, it's time to spin-up a child process to
   // handle decoding the video and building the gif

   var cmd = util.format('avconv -i %s/%s -r 8 -vframes 48 -f image2 %s/%s-%03d.jpeg && convert -delay 12 -loop 0 %s/%s*.jpeg %s/public/%s.gif && convert %s/public/%s.gif -layers optimizeplus %s/public/%s.gif', os.tmpdir(), id, os.tmpdir(), id, os.tmpdir(), id, __dirname, id, __dirname, id, __dirname, id);
   child = exec(cmd, function (error, stdout, stderr) {
       if (error !== null) {
         console.log('exec error: ' + error);
         client.sendMessage({
           to: phone, from: process.env.TWILIO_CALLER_ID, 
           body: 'Very sorry but an error occurred processing your video. Try a different video?'}, 
           function(err, responseData) { 
             if (err) {
               console.log('Error sending text: ' + err);
             }
           });
       }
       else {
         sendGif(host, id, phone);
       }
       cleanUp(id);
   });
 });
};

There are two ways in Node to start a child process:

exec
  and
spawn
 . The main difference between the two is that exec buffers output from the child process and returns it in its entirety and spawn streams output from the child process as it comes back. Since you aren’t interested in the output (stdout, stderr, etc) of the process you can simply use exec.

Exec takes a string that represents the operating system command that Node will execute. This command will be identical to what you executed manually earlier. The util module helps to format the command string with variables representing the operating system’s temporary directory, the UUID and the current directory of the Node process. Notice that you are chaining 3 processes together using the && shell operator. This has the effect of only executing subsequent commands if the previous command executed without error.

The second argument to exec is a callback. If any of the processes returned an error, send the user an SMS apologizing for the error. If there was no error, you can write a

sendGif
  function to send an MMS to the user that includes the generated animated GIF.

Step 6: Send Animated Gif Back to User

twilio_mms-3

In order to send an MMS back to the user you must construct a fully qualified URL to the animated GIF. Twilio will fetch the animated GIF from this location in order to construct the MMS that it delivers to the user. This is easy to do using the host information included in the request headers and the UUID you generated.

var sendGif = function(host, id, phone) {
 // an assumption made here is that the protocol is HTTP
 var gifUrl = 'http://' + host + '/' + id + '.gif';
 console.log('Success! Gif URL: ', gifUrl);
 client.sendMessage({
   to: phone, from: process.env.TWILIO_CALLER_ID, 
   body: 'Powered by Twilio MMS',
   mediaUrl: gifUrl}, function(err, responseData) { 
     if (err) {
       console.log('Error sending MMS: ', err.toString());
     }
   });
};

Step 7: Cleaning Up

Whether the exec process succeeded or not, make sure to clean-up all of the temporary generated files. The glob module makes it easy to get all of the files in a directory that match a given mask.

var cleanUp = function(id) {
  console.log('Cleaning up temp files');
  glob(os.tmpdir() + "/" + id + "*", function (err, files) {
    files.forEach(function(file) {
      fs.unlink(file, function (err) {});
    });
  });
};

Step 8: Testing the App

Save the

index.js
  file. Now it’s time to wire this app to your MMS-capable Twilio number and take this app for a test drive!

First, set the following environment variables:

export TWILIO_ACCOUNT_SID=xxx
export TWILIO_AUTH_TOKEN=yyy
export TWILIO_CALLER_ID=zzz

The TWILIO_CALLER_ID should be set to same number you’ll be using to receive messages on. Now, start the Node process: 

node .

Go to your Twilio account dashboard and click on the number you are going to use. Update the

Messaging Request URL
  to point at your VPS on port 3000 with a path of
/message
 . Make sure to select
HTTP GET
 , your code is expecting GET parameters to be passed. Click “Save”.

Phone_Number__747__900-4GIF___Dashboard___Twilio

The moment of truth. Send a short video (6 seconds or less) to your Twilio number. You should get an immediate response that your request has been queued, followed by a response that includes the newly minted animated GIF.

2014-10-06 13.30.31

Wrapping-up

In this blog post I walked you through using Node.js to convert videos sent to a Twilio phone number into animated GIFs. This included:

  • Spinning up an Ubuntu VPS with Node.js installed on Digital Ocean
  • Installing Libav and Imagemagick binaries
  • Using Node.js to orchestrate these programs and serve static files
  • Integrating Twilio to accept MMS videos and send out animated GIFs

There are two exercises left to the reader that are necessary to make this a more robust service:

  1. Using a job queue (like Bull) to handle the orderly processing of conversion jobs. This is important because the programs doing the conversion (acconv and convert) are CPU-bound and will quickly soak up system memory and resources.
  2. Configuring your server to run Node as a daemon and start the process on boot.

All of this code is hosted up on Github: https://github.com/crabasa/gifit

Hope you enjoyed this tutorial, happy hacking!

Convert Videos on Your Phone Into Animated GIFs Using Node, Libav & Imagemagick

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


CMO imperativesIn this digital era, the buyer’s journey has changed. Most CMOs are aware of this and are taking steps to adjust their strategies accordingly. But last week, EVP and CMO of CDW, Neal Campbell, sat on a panel with BMA Chicago and asserted that the task CMOs are faced with is more than a little tweaking here and there. In the age of anti-advertising—an age where 90% of consumers don’t trust advertising while 70% do trust what their peers have to say about a service or product—CMOs must undergo a major transformation, and if they want their businesses to succeed, there are six CMO imperatives they must meet head-on.

Mad Men Must Become Math Men

This is not to say ditch creativity. But your Mad Men and Women who you’ve relied upon to bring the creative juices must also dig into Big Data—and dig in deep. To successfully market to any audience today, you must have the right data to make the right decisions. Knowing who your customers are matters more than ever before. When you can create campaigns based around exactly who your audience is, down to the letter, you will have an easier time getting around consumer distrust of advertising. When the message is for them­—specifically them—and not for an ocean of generic leads, you’ll go far.

Maximize Investment in Brand Campaigns

When your audience doesn’t trust ads, where is a marketer to turn? For as long as we can remember—indeed, since the days of Mad Men—marketers have been tasked with creating ads and ad campaigns that reach their audience and convert them into customers. Now, statistics show that audiences are increasingly tuning out, finding ways to avoid “the pitch” almost all marketers spend vast amounts of time and money crafting, and instead find their own path to products and services. In this age, Campbell declared, all marketers must maximize investment in brand campaigns. With social platforms like Yelp, Facebook, and Twitter, consumers are relying on word-of-mouth to make purchasing decisions; they are looking for stories about businesses that will influence their buying journey. With that in mind, it is absolutely imperative that CMOs lead the way in their company to creating campaigns that focus around brand: not what your business sells, but who you are.

Find New Ways to Deliver Brand Story

IBM’s recent CMO study revealed that it’s still only a disappointing number of CMOs that have really invested in social media—many brands still put it off on their wish list, even with all the signs showing that social media is here to stay. Customers are online. If you want to succeed in the digital age, you must find new ways to deliver your brand story, and that means finding new places to deliver it too. Some of your customers have been on Twitter for years—when are you going to meet them there?

Equip Sales to Effectively Compete in the Evolving Digital Landscape

This means tapping into all the technology available that gets your sales force in contact with the people you want as customers. For example, mobile is exploding. More than exploding: it’s gone nuclear. Look at these stats. If you haven’t started implementing click-to-calls in your online ads, or at the very least begun putting phone numbers in your ads, you are not doing everything you can to 1) create better alignment between marketing and sales, and 2) give sales what they need to do their jobs better.

Get Human

Campbell emphasized this one strenuously. In a marketing era where customers are thirsty for stories and rely heavily on each other for influence on purchasing decisions, it is more important than ever to give your company a human face. Campbell started off his talk by saying CDW is composed of “3,600 live humans with digital fabric woven in.” The worst thing a CMO can do is forget that, even in the digital age, her audience is still human. This means getting social. Engaging. Getting on the phone. Doing face-to-face business. Don’t lose your humanity in digital marketing.

Follow the Customer

No matter what age we’re in as marketers, digital or otherwise, the ever-present CMO imperative is this: follow the customer. If he’s online, you get online. If she’s on her smartphone, you go mobile. Even when we don’t like it. Even when it’s hard. Even when it means unlearning everything we’ve ever known about our business. Because times change, and that means we must, too.

The post Mad Men vs. Math Men: 6 CMO Imperatives in the Age of Anti-Advertising appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 13, 2014

Share This: High call volumes, call spikes, repeat calls and the security needed to handle payment transactions over the phone all combine to make call […] …read more

The post What Prepaid Card Companies Need In Call Automation appeared first on Plum Voice.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


mobile marketingSmart marketers have known for quite some time what the rest of the world is just figuring out. Those smart marketers were quietly putting trackable phone numbers on their ads and webpages; they were including click-to-calls in their PPC ads and on their landing pages. But now—thanks to a myriad of studies proving once and for all that customers still want to “talk”—the word is out, and everyone else is catching on: calls are the new clicks.

Google’s Website Call Conversions tool has validated the need for call tracking, and even social media boss Twitter has been testing click-to-calls: Mountain Dew used a click-to-call tweet promoting Baja Blast and drove 3,500 phone calls. It’s a smartphone-driven world: we use our devices as they were designed­–as both phones and digital portals to the world. Now we as businesses are beginning to learn how to target them as both as well. With that in mind, here are ten stats that will—or at least they should—turn your head and make you think twice about what you’re doing with your marketing.

1. 25% of all search volume is coming from mobile devices. (Marketing Sherpa)

What’s more, Google and BIA/Kelsey estimate that mobile searches will surpass desktop search in the next 12 months. Searches are happening on mobile devices, and that means that the natural means of conversion is a phone call. Your marketing strategy has to make sense for where customers are finding you, and for smartphones that means making yourself callable.

2. 61% of people have a better opinion of brands when they offer a good mobile experience. (Latitude)

This means not only having a responsive site, but placing a phone number on your website so when that mobile browser is ready to convert, they can just tap and call.

3. 95% of smartphone users have searched for local info. (Google)

Focusing on local search shouldn’t be something your business is late out of the gate on. The fact of the matter is customers are searching right now, even as you’re reading this blog, and they’re searching on their phones. See next stat.

4. Google conducts 30 million click-to-calls each month. (SmallBizTrends)

That means that every month when customers execute a search, 30 million of them choose to be connected directly with a business over the phone, right there on the spot. What’s more, Google says 70% of mobile searchers have used the call button to connect directly with a business from the search engine results page. They could be calling you.

5. Mobile search will drive over 73 billion calls by 2018. (BIA/Kelsey)

If that number doesn’t make you want to double down on prioritizing phone call conversions, then you’re nuts.

6. 51% of mobile searchers say they “always” or “frequently” need to call a business from mobile search results. (Google)

What does this mean? It means that if you give them a chance, more than half of mobile searchers will call you directly from search. Let them.

7. 60% of mobile searchers state that click-to-calls are most important in the purchase phase of the shopping process. (Google)

Ever hear of shopping cart abandonment? Sure you have: if you’re an e-commerce biz it probably plagues you. (In 2013, as many as 73% of online shopping carts were abandoned.) Turns out, doing something as simple as placing a click-to-call on the landing or checkout page can keep that cart from being abandoned. Customers have questions during the checkout process: give them an easy way to get answers.

8. 47% of mobile searchers say they will explore other brands if a business doesn’t have a phone number associated with search results. (Google)

And why wouldn’t they? They’re on their phone searching for information now and rather than hunting around on your website on their small smartphone screen, they want to press “call” and speak to you directly to get all the answers they need, right away. Putting a number in your ad is a no brainer with stats like these.

9. Consumers across all verticals are likely to use click-to-calls. (Google)

In Google’s “The Role of Click to Call in the Path to Purchase,” Google examines customers in different verticals for the likelihood of their using click-to-calls. 69% for local services; 60% for auto; 51% for tech; 49% for travel. Think your industry is exempt? Not even close.

10. 57% of people who call a business do so to talk to a real person.

In the same study by Google, one of the top reasons customers used the click-to-call to contact a business directly was to talk to a real person. 54% called because they have questions or need more information than a website can answer. Thinking our websites can do all the work is wishful thinking. Your customers have questions and they want to talk.

Want to learn more about the implications mobile has on business and how you can capitalize? Check out this free on-demand webinar, 7 Commandments of Monetizing Mobile Search: What Every Marketer Should Know. Or you can call us. 877-295-5100. We’d love to talk.

The post 10 Stats About Mobile That Will Make You Think Twice About Your Marketing appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 10, 2014

It’s that time of year again. Dreamforce is approaching fast and we’re gearing up with our partners for an epic week of talks, tutorials, panels and more. We will be all over the DevZone, and Expo hall October 13-16th. Make sure to say hi to us in Moscone North Booth #N2113 and in Moscone West in the DevZone.

We want to make sure you get your fill of all things telephony and Twilio. Here’s where we will be throughout the week and where you can find some of our partners; NewVoiceMedia (Expo Booth 1921), Velocify (Expo Booth N2029), RingDNA, and OneReach.


Twilio Talks

  • Realtime Communication in the Browser Using Twilio and WebRTC
    Carter Rabasa shows you how realtime communications can change the way you communicate, Monday, October 13th, 11:00 AM- 11:45 AM, Moscone Center West, Innovation Theater
  • Customizing User Authentification with LoginFlows
    Charles Oppenheimer will walk you through customizing user authentication with Salesforce staff, Monday, October 13th, 4:00 PM – 4:30 PM Moscone Center West RM 2007


Twilio Sponsored Pre-Gala Event with NewVoiceMedia


Join us for a happy hour with our partners NewVoiceMedia, Tuesday October 14th from 5pm – 9pm at the Westin on 3rd Street
Register here


Catch Twilio Partner Talks Throughout Dreamforce

Monday

  • RingDNA CEO Howard Brown Hosts an Interactive Panel 5:00 p.m. – 5:40 p.m. Marriott Yerba Buena 13,14,15.
  • NewVoiceMedia- AppExchange for Service: Wow with Customer Service Apps 1:00pm – 1:40pm PT California East room, Westin St. Francis

Tuesday

  • RingDNA – Want To Leverage AppExchange as a Lead Engine?
    11:00 AM – 11:40 AM. The Westin San Francisco Market Street Stanford.
  • Velocify -How eHarmony Acquires Customers as Quickly as It Creates Love Connections 11:00am – 11:40am Marriott Golden Gate A Booth #N2029
  • OneReach – Escalate Your Support with free Desk.com for Partners 12:00pm – 12:40pm The Westin San Francisco Market Street, Olympic
  • NewVoiceMedia – Accelerating M&A and Innovation at Shell with the Salesforce1 Platform 9.30am – 10.15am InterContinental San Francisco, Telegraph Hill Booth 1921

Wednesday

  • NewVoiceMedia Maximize Your Salesforce Investment Across Sales & Service11:30am – 12:10pm Century Theaters, Theater 3
  • NewVoiceMedia AppExchange for Service: Wow with Customer Service Apps 2:30pm – 3:10pm Tower Salon A, Westin St. Francis
  • NewVoiceMedia Achieve a Multi-Channel Contact Center with One Integration
    3:00pm – 3:20pm Cloud Expo, Partner Theater North

#Dreamforce14: Where To Find Twilio & Our Partners

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


WebRTC is still an emerging standard, and as such you sometimes run into issues where it behaves differently on different hardware, different browsers, etc.

Today, we updated Twilio Client 1.2 to give you more control over the underlying WebRTC primitives, particularly getUserMedia, which allows you to gain access to the user’s microphone. This new feature allows you to maintain consistent audio quality in different audio environments.

Twilio Client normally takes care of audio issues for you, but sometimes you might encounter device-specific issues where it helps to manually adjust getUserMedia’s parameters. Twilio.js now allows you to pass through specific settings to the underlying WebRTC object.

Here’s one example where this comes in handy. One of our customers found that their audio devices didn’t work properly with Windows auto-gain control (AGC) features. AGC is designed to filter a microphone’s input volume dynamically based on the loudness of the source, so that the other end hears a consistent, even volume.

Unfortunately, one customer found that their AGC didn’t quite live up to its name. Whenever they made a call with Chrome on Windows, the operating system would slowly crank the microphone volume all the way up to 11. This was not an enjoyable experience for the person on the other end.

The source of the problem was that AGC was trying to find the right volume for the microphone, but was getting it wrong.

Thankfully, Twilio Client’s new

audioConstraints
parameter now allows you to enable or disable features like AGC by passing audio constraints directly to the underlying call to getUserMedia, allowing you to work around unusual, environment-specific problems like this one.

To avoid the “cranking it to 11” problem we previously mentioned, you could use

audioConstraints
to turn off AGC in Chrome through the
googAutoGainControl
parameter, as shown below:

Twilio.Device.setup(token, {
  audioConstraints: {
    optional: [
      { googAutoGainControl: false }
    ]
  }
});

This is just one example where it can be really useful to be able to pass parameters directly to getUserMedia. The new audioConstraints parameter is an optional second argument to Twilio.Device.setup(). Any parameters you pass in here will be sent through to getUserMedia.

For example, you could use audioConstraints to programmatically choose a specific audio device:

MediaStreamTrack.getSources(withSources);
 
function gotSources(sourceInfos) {
  var constraints = {};
   
  sources.forEach(function(source) {
    if (source.kind === "audio" && source.label === "My Device") {
      constraints.optional = [
        { sourceId: source.id }
      ];
    }
  });
 
  Twilio.Device.connect(clientParams, constraints);
}

We’ve put a more detailed example here. If you’d like to experiment with what values you can pass through, you can find a fairly comprehensive list of them here.

This feature is now available to everyone using the 1.2 release of twilio.js. Please let us know what uses you find for it!

Tweaking The Behavior of User Media Streams in Twilio Client

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Feature Friday is a bi-weekly blog featuring a new video brought to you by our Customer Success Team (CST). CST focuses on tutorials and feature enhancements that help our customers gain a clear understanding of how exactly they can make their Ifbyphone experience perfect. After all, we strive to be the easiest company you’ll work with!

Call center managers are constantly looking for ways to make sure that they’re offering the best service to their clients.  Being able to actively assist your call center staff is important as well. Luckily, Ifbyphone has put “Live monitoring” into play for our clients using the Call Distributor application.  Live monitoring allows call center managers to jump onto a call undetected unless they want to join the call.  Watch the video to learn exactly how you can enable and utilize this awesome feature.

The post Feature Friday: Live Monitoring appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


October 09, 2014

lte_asia_20141
Last week in Singapore, Tropo was chosen as the winner of the Innovation Accelerator award during the LTE Asia Conference. Now in its 9th year, the LTE Asia Conference brings together over 1000+ high-level attendees  (60%+ of whom will be representing operators) from 50+ countries across the APAC region and beyond , bringing together the ecosystem to discuss a wide range of issues including monetzing LTE, hetnets, network optimization, LTE evolution, 5G and more.

This was the first year the event included an awards ceremony and we’re extremely excited to have won the Innovation Accelerator Award, specifically in response to our work with APAC partners China Telecom and Globe Philippines, both who have rolled out Tropo to their ecosystem partners.

LTE World Series Blogger Benny Har-Even caught up with Tropo’s APAC General Manager, Fuxin Jiao-Kiuru shortly after the award was announced and put together this inteview:

http://lteconference.wordpress.com/2014/09/30/interview-general-manager-tropo-while-we-are-a-small-and-agile-organisation-and-can-react-fairly-fast-thats-not-enough-we-need-to-have-everyone-along-the-delivery-chain-moving-q/

The post Tropo Wins Innovation Accelerator Award appeared first on Tropo.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Have you ever had a night where you feel like everything funny you say lands on deaf ears, only to have an unplanned, half-baked comment make everyone bust up laughing? I think it was Louis CK who said “…simple truth beats out cleverness every time”. I thought of this a few weeks ago when I was showing some of my colleagues an SMS demo I had made that would send a user a text message once they enter their phone number. I had hoped they would find the demo interesting, but it turns out they were more interested in the resulting text that was sent which included a Twilio logo in the message. As an offhand comment my buddy Matt Makai asked “is this a branded SMS?” Which is how the idea of “branded SMS” was born.

Of course, we didn’t actually create branded SMS, it’s more of a design trick. By sending an MMS with an image that looks like a standard text message with a logo on it, we create the illusion of a branded SMS. It may have been an accidental discovery, but it has the potential to be a very cool way of engaging your user base.

To send yourself a branded SMS text ‘hello’ to:

(979)272-6399

 

windows-feature.jpg

 

 

How Branded SMS works

Pretty easy right? The only piece of code you would need to add to your server is the 4 lines necessary to send an MMS. The hardest part is actually creating the image that looks like a branded SMS, so let’s start there.

Creating the image to look like an SMS

The first step is to create an image that looks like an SMS across different devices. When I started working on this I realized there were a few challenges. First, I had to figure out how these images would render on different devices. Unfortunately I had to do this by trial and error since I was unable to find a developer guide that succinctly explained how MMS are rendered across different devices. So I borrowed friends devices, sent the MMS and iterated. The results are not perfect but at least convincing to the casual observer.

The next challenge is how do you decide which image to send? In other words, how do you know an iPhone user is receiving iOS looking branded SMS? There are few approaches to finding this information. Ideally you would have someone visiting your website or app on their mobile device before you initiate the branded SMS. In this case there are many ways to detect the device depending on whether it’s the web or a native app. In my demo I took a much less elegant approach and I simply asked the user. If you think of a super creative way around this problem feel free to share with me on twitter.

Luckily the fruit of my labor is available to you so that you don’t have to start from scratch. To help you get started I have included a few templates that have some SMS styles for iOS, Android and Windows.

sms-templates

Templates: illustrator, eps, pdf (download now)

Once you’ve created your own image be sure to export it as a jpg or png. Now all you need to do is host the image at a public url (dropbox, Amazon S3, etc) and you are ready to send your first branded SMS.

Sending an MMS with Twilio

We’ve been writing a lot about MMS so I’ll keep this short and sweet, but if you’d like a more in-depth look at how to get started using MMS definitely take a look at Kevin Whinnery’s post on the subject.

In the case of my demo, I wrote the server-side code in Ruby/Sinatra. The advantage of Sinatra is that I can write one little file and deploy to heroku. Here is the snippet that sends the MMS:

# Branded SMS Webhook: first asks for device -- then sends MMS
route :get, :post, '/branded-sms' do
  $DEVICES = {
    "iphone" => {
      "url" => 'https://s3-us-west-2.amazonaws.com/deved/branded-sms_ios7.png',
    },
    "android" => {
      "url" => 'https://s3-us-west-2.amazonaws.com/deved/branded-sms_android.png',
    },
    "windows" => {
      "url" => 'https://s3-us-west-2.amazonaws.com/deved/branded-sms_windows.png',
    }
  }

  @client = Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
  @phone_number = Sanitize.clean(params[:From])
  @body = params[:Body].downcase

  deviceList = ($DEVICES.keys).join(',')

  if deviceList.include?(@body)
    pic = $DEVICES[@body]['url']
    puts pic
    message = @client.account.messages.create(
      :from => 9792726399,
      :to => @phone_number,
      :media_url => pic,
    )
    puts message.to
  else
    @msg = "What kind of device do you have? Reply: 'iphone', 'android', or 'windows' to receive a branded SMS"
    message = @client.account.messages.create(
      :from => 9792726399,
      :to => @phone_number,
      :body => @msg
    )
    puts message.to
  end
  halt 200
end

And with that, you have sent a super cool looking branded sms.

Wrapping Up

It may have been a total fluke that we ended up creating branded SMS over here at Twilio, but with the collective brilliance of all of you Twilio doers, I’m sure this concept could become a movement. What if you created an SMS with custom emoticons? Or how about leveraging the fact that you can send animated gifs using Twilio and create Messages that morph? The potential is pretty cool of hacking the SMS interface, and I look forward to seeing what you all create.

If you have ideas on hacking SMS or if you just need someone to hold the ladder while you graffiti fake logos on the sides of shopping malls, shoot me an email or find me on twitter.

How to Send Your Users a Branded SMS using Twilio MMS and Illustrator

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


VitalsIt is no secret that healthcare has made a migration towards the Internet. Between the abundance of online information and higher insurance rates, hospital Between the abundance of online information and higher insurance rates, hospital revenue growth has been on the decline. In fact, 2013 revenue growth dropped to 3.9% from the previous years growth of 5.1% (Moody’s Investor Services). This has left hospitals and other healthcare providers scrambling to attract attention through digital channels in order to stimulate their patient levels. Ad Age recently posted an article detailing the importance of digital marketing for the healthcare industry. The article states that hospitals, clinics, and medical centers spent about $1.8 billion on U.S. measured media last year, and a lot of the media spend is being designated towards online marketing.

Healthcare Marketing Shifts to Digital

Healthcare marketing has transferred its focus to digital media channels, and for good reason. Instead of going straight to a doctor, tremendous amounts of people are first performing Internet searches in an attempt to diagnose their symptoms. The Internet is not always the most accurate diagnostic tool; so many people still end up seeking out an opinion from a professional.

The next step becomes finding the right physician, clinic, or hospital to visit, and social media has had a huge impact in this process as well. Online healthcare listings and reviews have become a huge source of new patients for providers. Driving appointments through online marketing has become one of the most successful channels for medical practices. With the amazing popularity of smartphones, a significant number of online medical information is being found through mobile. Between mobile search and the popularity of healthcare apps, patients are finding a care provider on their smartphones.

Online Marketing for Healthcare Drives More Appointments

Thanks to smartphones, people are responding to online marketing by calling doctors to make appointments more than ever. Google reports that 61% of mobile searches result in a phone call. Getting a potential patient on the phone is one of the fastest ways to convince them to schedule an appointment, and in turn drive more business for healthcare providers. Knowing where those calls are coming from is incredibly important for optimizing online marketing efforts and understanding which online sources are driving calls and appointments.

Marketers tasked with lead generation for healthcare providers have an easy enough time tracking prospective patients through online channels, but when that prospect picks up the phone to call in for information or to schedule an appointment, they are lost to the marketer. In order to remedy this issue, marketers have turned to call tracking. Call tracking allows marketers to attribute each and every phone call back to its original source, enabling marketers to optimize the marketing efforts that drive calls and appointments, as well as providing the ability to prove the impact on the bottom line.

How Vitals Uses Call Tracking

One company that has found huge success through call tracking is Vitals. Vitals’ websites, which include Vitals.com and UCompareHealth.com, are the source of highly credible reviews and valuable research on healthcare providers. Vitals’ enhanced listings promote their clients’ healthcare services on prominent sections of their websites. With roughly 10 million monthly visitors to their websites, Vitals drives a lot of appointments for their clients.

For Vitals, proving to their clients the volume of calls they are generating is a top priority. To do so, they turned to Ifbyphone’s call tracking solution. Vitals uses call tracking numbers on their enhanced listings to prove that each call came from their enhanced listings, regardless of whether the caller dialed the number on a landline or called from a click-to-call link on their mobile phone. Call tracking data is then integrated with Vitals’ own custom reporting system so they can present their clients with robust analytics and truly demonstrate the ROI they provide.

In order to further enhance the value they provide their clients, Vitals also incorporated IVR (interactive voice response) into their services. They use IVR to qualify inbound callers and then route them to the appropriate place. This makes it possible to weed out the people who want to schedule an appointment from those who are just looking for information.

Using call tracking, Vitals was able to demonstrate how their clients experienced a 7.5x increase in call volumes and appointments. To learn more about how Vitals uses Ifbyphone to drive results, check out our case study: Vitals Uses Ifbyphone to Prove How They Drive 7.5 Times More Appointments to Healthcare Providers.

The post Vitals Enhanced Listings Drive 7.5 Times More Calls for Healthcare Providers – And How They Prove It appeared first on Ifbyphone.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Last updated: October 23, 2014 04:01 AM All times are UTC.
Powered by: Planet

Speech Connection and Logos are Trademark of Nu Echo Inc. Copyright 2006-2008.