Reintroducing StubHub Mobile Web
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.
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:
- Responsive web design, which was critical for tablet users.
- Better i18n support for future domains, like UK, EU sites.
- Improved location-based search for popular events, teams, artists, and shows.
- Event screen displaying tickets grouped by section.
- Interactive venue maps, and view from section.
- User-friendly URLs that follow the same structure as our full website and can be easily read and bookmarked.
- Improved page loads and AJAX calls, resulting faster page loads.
- ESPN API integration enabling us to display teams grouped by league.
In this section, I’ll review some technical changes we applied to the our new mobile website.
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
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
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:
- When user takes an action on the page,
replaceStatewill be called, browser URL updates,
onpopstateevent handler will be triggered to handle page updating.
- When user clicks back or forward button, browser URL changes,
onpopstateevent handler is then called.
- When user opens a valid URL, we initiate a mapping state, and
pushStateit, and then
onpopstateevent 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
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:
- Phone portrait (width ≤ 500)
- Phone landscape / medium tablet portrait (500 < width ≤ 760)
- Medium tablet landscape / large tablet portrait (760 < width ≤ 1020)
- Large tablet landscape / desktop browser (1020 < width)
Scalable front-end framework with MVC
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
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
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
So how does our new mobile website stack up to our old one?
- 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).
- The count of HTTP requests has dropped from 28 to 11 on page loads.
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
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.
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.