« September 2011 | Main | April 2012 »

November 2011


Mission: Mobile Makeover

As previously reported, we recently released a brand new mobile site, hand made with love for our more than 8 million users with mobile Webkit browsers who visited www.yelp.com from mobile devices in August.

Surprisingly, there are a lot of challenges when creating a whole new, albeit mini, website (who would have thought?).

If you were to look online for guidance on designing a mobile website, you would come across lots of articles that cover three main considerations:

  • The once precise cursor is now your chubby, fumbling finger
  • You have to present a lot of data on a wee-small screen
  • Wireless networks, no matter what commercials say, tend to be slow

We aren't going to reiterate those challenges here today. Instead, we will discuss some lesser publicized challenges and opportunities that we at Yelp were presented with.

For the first iteration of the mobile site, we wanted to focus on the ease of discovery.

Users are goal oriented on mobile devices; they want to get from their home screen to their destination as fast as possible and with the least amount of distraction. So naturally, our big question was “how can we help our users find great local businesses as easily as possible?”

Although Siri tries, there is no silver bullet. The answer is multifaceted and involves both technical and design decisions.


Making the design unobtrusive and useful

When you type “yelp.com” in your smart phone browser, you are instantly directed to our new mobile site and the first thing you see is a search bar. No frills, no meaningless decoration, no lengthy explanation of what Yelp does (because who doesn't already know!).

Directly underneath the search bar is a list of categories. No header, no extraneous explanation that these are categories, no distractions.

Finally, just below the category list, we show off one of our newest features: Hot New Businesses.



Without even scrolling the page we have covered three user profiles: the hurried user that knows exactly what he wants to find, the user that knows she wants to find something and the user that is just casually seeing what’s new around them.

Once clicking through to a business page, you will immediately see a map of the business and calls to action for getting directions or calling the business.

If you are still undecided about the business, scroll down to quickly consume short but helpful commentary using Photos, Review Highlights and Quick Tips.

Meanwhile, users that have a bit more time on their hands (jealous) can keep scrolling and read full-length reviews about the business.

Once again, we have catered to three user profiles (concentrated, curious and casual) in order of their immediacy.


a business page on yelp mobile


Leisurely users are likely sitting on a comfortable sofa and can afford to flick the page around and browse longer-form content. However, the on-the-go (read: mobile) user needs to immediately see the tools that they need to complete their goal with ease and without distractions.


Making the design understandable

Giving the user the appropriate content in the appropriate place is a huge step to our overall goal. However, if the user doesn’t know how to interact with the content, it is all for naught.

Even though a huge win for mobile sites is the "code once, run anywhere" principle, there seems to be a knee-jerk reaction to make everything look and behave like the iPhone. This is wrong and something that we were guilty of.

There are at least two reasons why that way of thinking is harmful:

  • Our friends on Android, Blackberry or Windows 7 phones aren't familiar with the iOS design patterns. While the "Save" button in the upper right of the title bar, the red notification indicator and the dock-style navigation bar are great conventions; they are foreign on non-iOS users.
  • All those sexy animations and gradients that are laced throughout the iPhone's interface are nearly impossible to render smoothly, if at all. Even on the newest iPhone, Javascript and CSS animations won't feel snappy like users have grown accustom to. And when (inevitably) they don't work like native interactions, the user will feel like something is wrong, or at the very least, janky.

 A common solution for this is to progressively enhance the site based on the device it's running on. However, a much more efficient approach is to design a website that doesn't strictly adhere to a certain device's guidelines. For this we can draw inspiration from the Bauhaus movement of the 1930's and what they called "International Style"; a style that was universally applicable, acceptable and welcoming. This sort of aesthetic is much more in-line with the "code once, run anywhere" principle.

When creating this hybrid aesthetic, you have the opportunity to synthesize all the best parts of native interfaces, common conventions from web browsers and your brand's visual language.

In our case, we implemented iOS-style clickable list-items, standard plain-text styling for links that take you out of the Yelp flow and an Android style loading screen – all while maintaining a Yelpy feel!

While tailoring the design to each device could potentially provide the best user experience, it is a slippery slope, as you may be supporting N devices in the future.

From content organization to button styling, our new mobile site made us re-evaluate our product. We had to sit down and focus on what we do best, helping people find great local businesses. We still have a lot to learn and a lot to build, so stick around - we are just starting. And if you have feedback, let us know at mobile-feedback@yelp.com!



Output Filtering Failure

About a month ago, we launched m.yelp.com specifically targeting iPhone, Android, and WebKit-based smart phones. Our engineering team pushes code live on average three times a day. Moving fast means we need to have sound engineering practices internally — such as code reviews by peers and automated testing tools such as unit-tests and static analysis — to catch mistakes before they happen. In this blog post we will detail a misstep that we made and the response that followed.

On the morning of October 27, 2011, we were alerted by a team of researchers at Harvard, Yale, and Boston University that they had found a servlet on m.yelp.com that could expose private user information. Working jointly with this team, our engineers gained a full understanding of the exposure. The leak allowed clients to see a JSON dictionary with user-specific fields, including email address, birth date, gender, and full names. No financially sensitive information was exposed.

Once we understood the risk to our users we immediately took the mobile site down. We resolved the issue within an hour, but kept the site down for 12 more while we double- and triple-checked for other issues (none were found). We analyzed the servlet’s access logs to see if anyone exploited the hole, but we did not find any evidence that user information had actually been collected. We also created an automated system to detect sensitively named fields (last_name, birthdate, etc..) being sent to clients. Following this work, we felt comfortable that the risk of a future exposure of this type had been mitigated; so we turned the mobile site back on.

The servlet at issue was using an ORM to retrieve information from the database. An ORM (object-to-relational mapper) system that automatically creates objects containing database content may make it easy to access that data, but it also introduces risk if those objects are not sanitized before being passed across a trust boundary. In this case, we missed a sanitation step in a servlet when grabbing data from the ORM.

Our python logic for the biz details servlet looks like the following:
def reviews(self, businesss_id):
     “““unsafe version of reviews()“““
    reviews = self.get_business_reviews(business_id)
    return json.write(
        # UNSAFE CODE: unsanitized data going to the
        # client DANGER!
        {'reviews': reviews}

In the code above, the call get_business_reviews() under the covers returns data about reviews, including details of the users who wrote the reviews. This is where the private information on the user is requested.

To illustrate, here is an example JSON response from the offending servlet:
{'reviews' : [...
           'user': {'birthdate': '1971,01,01',
                    'display_name': 'Art G.',
                    'first_name': 'Art',
                    'gender': 'm',
                    'last_name' : 'Goldfin', 
            }, …]
Note: birthdate, gender, and last_name are all private fields that shouldn’t have been returned in the JSON response.

The above servlet function reviews() was rewritten to (approximately this):
def reviews(self, business_id):
    “““output filtered version of reviews()“““
    reviews = self.get_business_reviews(business_id)
    # Filter reviews to contain only data necessary
    # for frontend
    safe_reviews = filter_for_frontend(reviews)

    return json.write({'reviews': safe_reviews})

In the second implementation of the reviews() function you can see that the reviews object is transformed by filter_for_frontend() before being written into the JSON response.  We’ve also modified json.write() to have a list of sensitive fields that will throw an exception if an engineer tries to pass a field with a restricted name like last_name, birthdate, etc.. With these protections in place, we’re well protected from this type of exposure in the future.

We’d like to thank researchers at Harvard, Yale, and Boston University:

We appreciate the team’s diligence in finding and notifying us about this important problem; their thoughtful handling of a sensitive and tricky security situation is commendable. If you do find any security-related issues on Yelp, please send an email to security-abuse@yelp.com.

Yelp’s Engineering team is committed to excellence in engineering and data security; this incident was responded to with full force. Keeping user data safe is a top priority for Yelp, and we’ve taken concrete steps in response to this incident to make sure that it will not happen again.