Reintroducing StubHub Mobile Web

Introduction

As you may know, the new StubHub Mobile Web is now alive. If you have an iOS device, and you might have already used it by accessing http://www.StubHub.com from your mobile browser. In this article, I’ll share some insights around how we implemented the new StubHub mobile website, as well as the new features and improvements we introduced.

New features

Before starting to redesign and develop our new mobile website, we – StubHub Mobile Web team – collected and reviewed tons of user experience research and analytics reports. Based on our analysis, we prioritized and defined the new Mobile Web. Here are some of them:

  1. Responsive web design,  which was critical for tablet users.
  2. Better i18n support for future domains, like UK, EU sites.
  3. Improved location-based search for popular events, teams, artists, and shows.
  4. Event screen displaying tickets grouped by section.
  5. Interactive venue maps, and view from section.
  6. User-friendly URLs that follow the same structure as our full website and can be easily read and bookmarked.
  7. Improved page loads and AJAX calls, resulting faster page loads.
  8. ESPN API integration enabling us to display teams grouped by league.

Technical highlights

In this section, I’ll review some technical changes we applied to the our new mobile website.

User-friendly URLs

If you’re familiar with the old StubHub Mobile Web, you’ve probably noticed the long hash string appended to each URL. This string is actually an encoded JavaScript object which is used to store the essential page status and display settings, and results in super long URLs – sometimes it occupies 3 to 4 lines’ worth. This extra long URL could be confusing to both users who want to share event info with their friends (Will this link work?) and the recipients of the event (What is this long string of characters?).

The new StubHub Mobile Web URLs are as intuitive as the full site URLs. For example, when you browse to a San Francisco Giants’ game, you will see http://touch.stubhub.com/san-francisco-giants-tickets as the URL, and when you select a specific game, you’ll see http://touch.stubhub.com/san-francisco-giants-spring-training-tickets/giants-vs-dodgers-3-8-2013-4186735. Every browse page you visit on the our new mobile website has a readable URL that corresponds to the equivalent page on our full site. And if you receive a URL from someone, you can get a sense of where the URL will lead you.

In addition to being more intuitive and user friendly, this improved URL structure is helpful for SEO and paid search. With the new implementation, every team, artist, and event has its own corresponding URL, as well as HTML meta elements for page title, keywords and descriptions. When the URL changes, the corresponding HTML meta elements are updated as well.

Better history management

Our new mobile website is a single page application, which means that once you have loaded all the resources (HTML/JavaScript/CSS) from StubHub, all of following requests are handled through AJAX. Since handling user’s action history (particularly when users try to go backward and forward) can be problematic with AJAX, our new mobile website leverages the HTML5 History API. This means we could only listen to the onpopstate event for any navigation action taken on browser itself. Checking out the following links for more information about the History API

Basically, HTML5 History API defines a few methods for us to track statepushState, replaceState, getState, and a onpopstate event to listen to. By using these API in our mobile web, we associate each state with a specific URL (mentioned in above chapter). A few cases are listed as below:

  1. When user takes an action on the page, pushState or replaceState will be called, browser URL updates, onpopstate event handler will be triggered to handle page updating.
  2. When user clicks back or forward button, browser URL changes, onpopstate event handler is then called.
  3. When user opens a valid URL, we initiate a mapping state, and pushState it, and then onpopstate event handler is triggered.

What we did was to provide a consistent onpopstate event handler to cope with all these cases.

Unfortunately, the HTML5 History API is not perfect. During development, we found that the History API is not equally supported by different mobile browsers. Here are some examples:

1.On iOS5 Mobile Safari, users encounter issues when they leave the mobile website and try to come back again by tapping the ‘Back’ button.  2.On Android Chrome, there’s no native way to get to the current state.  3.On some of Android stock browsers, URLs don’t update after calling the pushState.

To address the unique challenges and behaviors of each mobile browser, we developed our own history management module. For browsers that don’t support the History API well, we provided history management based on the location hash.

So far, we’ve applied HTML5 History API on Mobile Safari on iOS v5.0+ and Chrome on Android v4.0+. And for Android stock browsers and other browsers like Opera Mobile, BlackBerry stock browser, we leveraged location hash to manage the user’s history. This means you might see URLs like http://touch.stubhub.com/nba-tickets/ and http://touch.stubhub.com/#/nba-tickets/ – but they’re really the same thing.

Responsive design for all sizes of handsets

We completely redesigned our mobile website using responsive web design, optimizing the viewing experience based on the device type, screen size, and orientation. For example, on smartphones, we provided a push-in navigation menu, while on tablets the navigation menu is persistent and you can either expand or minimize it. Given the limited real estate, we show the venue map and ticket listings on different screens, while on tablets we use two columns to display the map and filtered ticket listings at the same time.

If you play around with StubHub Mobile Web on both a smartphone and a tablet, you’ll notice more visual differences between the two experiences. These differences are achieved by what is commonly known as a CSS media query. We’ve defined four sizes for all handset types based on screen width:

  1. Phone portrait (width ≤ 500)
  2. Phone landscape / medium tablet portrait (500 < width ≤ 760)
  3. Medium tablet landscape / large tablet portrait (760 < width ≤ 1020)
  4. Large tablet landscape / desktop browser (1020 < width)

Besides using CSS query for the display, we also use JavaScript code to handle the logic differences for different device sizes. When initiating each UI component, the size is passed in as parameter.

Scalable front-end framework with MVC

The new StubHub Mobile Web is built upon the concept of Scalable JavaScript Application Architecture. We use the scaleApp as the Core, and its MVC plugin, which is quite simple and lightweight.

ScaleApp is pluggable, enabling to develop our plugins to wrap it into a customized framework. We’ve developed over 10 plugins to meet the requirements, like the URL management plugin, History management plugin, SEO plugin, Omniture tracking plugin, Utility plugin, and i18n plugin. The scaleApp and all these plugins work as the core and base, providing lots of business and function related APIs for UI modules to use via sandbox.

On top of the Core, we have developed modules which work as layout or UI components. We also developed a few common modules like EventList and GenreList which are reused in UI modules. These UI modules follow the MVC pattern, so when a user takes an action or some customized events are captured, we change the data in Model, which will then trigger the corresponding View updates.

During development, and after we’d developed a few modules, we created a template allowing us to quickly build new modules. This template file extends the MVC structure, defines the life-cycle methods (such as init and destory), and generates stubs for creating views and binding/unbinding HTML/global events. By filling these pre-defined methods and renaming names first, a new module could be built easily, and would be in a good shape. Mostly importantly, this template helps developers not only focus on the business logic without missing any trial things, but also makes the module codes easier to maintain.

Keeping performance in mind

Before we started developing our new mobile website, we had a few baselines in mind: load less resources, avoid unnecessary requests, and reduce the size of REST call responses. Next, I’ll cover how we dealt with improving performance.

Creating a smaller footprint

Our new mobile website uses jqMobi to target WebKit browsers in particular. Compared to jQuery, jqMobi is much smaller in size and performs almost as well. This is just one of the ways we made the footprint increasingly smaller. While there are lots of JavaScript libraries that are widely used for web development (underscore.js for utility, backbone.js for MVC, History.js for managing browser history), we didn’t choose these libraries because they didn’t quite fit our needs. Instead, we wrote our own libraries exactly tailored to our requirements. These libraries work in the form of ScaleApp plugins, and provide all the necessary functions, including history management, URL management, SEO, tracking, i18n, templating, LocalStorage management, global variables management, and a few utilities on StubHub data objects manipulation.

So how does our new mobile website stack up to our old one?

  1. The size for these JavaScript files (working as our core libraries) has been reduced from 120+ KB to ~90 KB, and 30+ KB of which are now dedicated to drawing interactive venue maps.
  2. In all, the page loads (for all artifacts) have been reduced from ~300 KB to ~200 KB (without calculating the REST call responses which are used to generate the first page).
  3. The count of HTTP requests has dropped from 28 to 11 on page loads.

Leveraging LocalStorage

To improve page responding time, the new StubHub Mobile Web makes full use of LocalStorage which most modern mobile browsers support. According to this Web Storage Support Test, our supported mobile browsers have as many as 2.49M characters volume for LocalStorage. For us, this means that LocalStorage could be used to store over two thousands event data or four thousands genre data.

Event data and genre data are used everywhere on StubHub. When you browse on StubHub, you will get information about your selected events, sports teams, or artists. This information rarely changes once it’s created in the database. Therefore, we decided to cache event and genre information to LocalStorage once a user browsed to that event or genre. We also cache user-related information like the sports teams in their cities, and their favorite teams and artists. Even though LocalStorage provides enough volume for our business, we still provide a mechanism to remove expired data.

The advantages of applying LocalStorage are that it could prevent unnecessary AJAX calls and improve application response times, benefiting users. For example, when you open an event page URL on our old mobile website, we query the event information from server before displaying the venue and date to the user, so you need to wait for it. But on our new mobile website, once the HTML loads, you’ll see the event information immediately.

Using lazy load images

Images consume resources for mobile browsers, both in terms of time and CPU. During development, we encountered a situation where ~80 view-from-section images began to load at the same time. Even with a WiFi connection, we saw that the browser wasn’t responding for up to a few seconds. As a result, we stared thinking about using lazy load for images.

Most examples of lazy loading images showed that we needed to bind event handlers to these images. However, we can’t bind events to images as the images we display are generated in runtime. For example, when you browse to a San Fransisco Giants game, about 80 view-from-section images are generated, and when you switch to see Golden State Warriors game, these 80 images are removed and another 70 images are generated. In these cases, binding events is not a good condition. Another drawback of these lazy-loading examples, is the abuse of offset and getClientRects. These methods trigger reflows (see this), which is a CPU consuming job. If there are only a few images on the page, that wouldn’t be a problem. But on some of our pages, we may have as many as 100 images. If we continued loading images this way, every scroll would lead to hundreds of reflows.

How did we resolve this? Hard code! Since each image is contained in a list item (row) and the list item has a pre-designed height, we use the height of list item – a hard-coded number – to calculate how many rows are scrolled over. The benefits of this solution are two-fold: (1) we only need bind one onscroll event handler to the list, and (2) it only reflows once (getting the scrollTop) when one scroll event triggers.

Conclusion

This article highlighted our experience developing StubHub’s new mobile website, including some of the challenges we encountered and the performance enhancements we developed. In the near future, we’ll dive into specific mobile web topics. Stay tuned.

About the author

Kevin Guo is a UI developer at StubHub where he focuses on mobile web development since 2011.

©2012 StubHub, Inc. All rights reserved.