PWA at L’Équipe, a case study

L’Équipe Tech
Published in
8 min readJan 3, 2018

This story is the translation of our article originally written in French La genèse de la Progressive Web App à L’Équipe.

In August 2017, L’Équipe was one of the first French websites — 1st big media website — to launch a Progressive Web App (PWA) [FR]. It was one of our flagship projects early last year and it’s still keeping us busy today.

Since the launch, a number of colleagues who are very interested in this innovation — which is more and more encouraged by Google have contacted us. They wanted to know more about our initial goals and technical choices but also the impact on traffic. This is why we decided to write this article about the story of our PWA, in order to share our experience and hopefully help you to take the right decisions.

Before you read this article we recommend you have a basic understanding to what is a PWA.

What did we want to achieve?

In addition to revisiting the design of the old webapp, the goals of the redesign were mainly to:

  • Retain mobile website users, who are mostly occasional visitors coming from social networks or search engines
    -> only 3 pages per visit versus 8 for native applications
  • Improve performances
    -> optimise load time, navigation speed, animations fluidness
  • Offer an offline mode
    -> being able to read offline an article that was previously loaded
  • Update architecture relying on dynamic APIs
    -> use the same APIs as native apps and build new ones
  • Innovate :
    -> attract or retain the best developers through technical challenges

All goals listed here shared the same objective: turn the mobile website into a growth engine for L’Équipe.

How did the project unfold?

Thinking phase

The first challenge before the project started was to convince internal stakeholders. For this purpose, we prepared a formal presentation to explain what is a PWA, why we believed this technology would emerge and be relevant for our mobile website and how we could implement. Once acknowledged and estimated (5 months to cover a first perimeter), we launched the development phase.

Development phase

To prepare the way, we first set up a very small team made up of 2 lead developers and a Product Owner for the business part. After a first pace (4 sprints of 2 weeks each), the team was extended: 2 front developers, 2 back developers and a PO. The Scrum Master role was played by one lead developer.

Testing phase

During the 3rd pace, we were ready for a first release and collected feedback from our users. The PWA was deployed on a dedicated subdomain concurrently with the old webapp. The latter displayed a popin inviting our users to try the beta version.

Although this phase was quite short, it allowed us collect useful feedbacks through a Typeform form and fix some bugs that were quite difficult to test internally. It was clearly successful.

However, the downside is that a minority of dissatisfied users often tend to speak more loudly than the rest. The risk here is to start getting overwhelmed by doubt when faced with negative comments (usually not even constructive…).

Production phase

After one month in beta and having fixed all showstoppers, we switched all the traffic from the old mobile website to the PWA. The work is not finished yet. Lots of templates remain on the old webapp and need to be gradually migrated.

What is our technical base?

The shell

Google recommends to create one HTML file as a shell, easily cacheable and gathering all needed resources to run the PWA offline.

Our first attempt was to compress all CSS and JS code into index.html. It is probably viable on a light website. But not when the shell weights nearly 600KB, which is our case.

By compacting the JavaScript into HTML, it was impossible to make it asynchronous. The display of the First Meaningful Paint was impacted. Users therefore saw a blank page more or less slow depending on the quality of their network.

Secondly, our CDN is set to cache JS and CSS files for a long time, unlike HTML files which have a very short TTL. Our bandwidth exploded.

The solution was to completely review this design. We rolled back to a more traditional but adapted architecture: compact the minimum viable CSS into the HTML to display a loader very quickly ; then load the remaining CSS and JS asynchronously.

We reached a much more satisfying critical rendering path, as measured below by Lighthouse, the performance audit tool:

PWA in slow 3G

Service Worker

Theoretically, the Service Worker (SW) is the cornerstone of a PWA and manages the entire cache strategy of the app. In practice, SWs are not currently supported on iOS — but will soon be[FR] — which made it difficult for us to explain to the product owner that iOS users, including on Chrome, would have a worse experience than on Android.

To get around this constraint and after communicating with Google who gave no counter-argument, we set up an application cache system based on local storage. We only used the SW very partially for the Add2Homescreen and the caching of the shell, the only features reserved for Android users.

JavaScript framework selection

Using a JS Framework is not mandatory to build a Progressive Web App. Nevertheless, one of our goals being to share the APIs with our native apps, it seemed pretty obvious to choose a Single Page Application (SPA) and therefore a JS framework.

But which one?

AngularJS (1.x) had the advantage of being well controlled internally and therefore quick to set up. Unlike Angular and React, which although more modern and offering the option of server-side isomorphism, were much less in control.

Essentially for timing reasons, we chose Angular 1.6, with a component-based architecture that allows us to leave the door open for a later upgrade.

In the end, reading this article comforted us in our choice.

Retrospectively, because the size of JavaScript was our main constraint in terms of performance, choosing not to migrate to Angular 2 (5 now) proved to be a wise choice given its huge weight.

React or Vue could have fit our needs, but ramping up the team’s skills on such a big project was a major obstacle.


You can’t develop a SPA without thinking about SEO, a strong challenge at L’Équipe.

Since Angular Universal was only available from Angular 2, our alternative for generating easily searchable pages by search engines was to choose

With a relatively low cost (a few hundred euros per month for 800,000 indexed pages) the service fulfilled its promise, even if it forced us to adjust our CDN setup on a case-by-case basis.

This is the price to pay for not having chosen a more modern framework, we assume it.


Another important issue, especially when it comes to mobile, is performance.

We quickly realized that by gradually adding new types of pages in the PWA, its size would increase, leading to a negative impact on performances.

Thanks to the oclazyload plugin, we reviewed our approach: now, the core of the application is composed only of homes and pages of articles. Other types of pages (HTML templates, CSS styles and JS controllers) are lazyloaded so as not to penalize the first load.

The drawback is that the offline mode can be considered only for components embedded in the application and not for the whole site.


Each feature developed for the PWA is automatically tested every release.

We use the recommended ESlint configuration to automatically check and correct code syntax, Karma coupled with Jasmine and ChromeHeadless for unit tests and Protractor for functional tests performed on each type of pages.

And now?

With nearly 80% of the traffic coming from mobile devices (PWA and native apps together), developing the PWA remains at the heart of our strategy. Here are two examples of future developments:

  • PWA at the service of native apps
    The arriva of the PWA has been an opportunity to challenge our native apps in an offline environment. After some research on the subject, we’ve been working together to develop an in-house solution to embed the shell of PWA into apps in order to inject JSON feeds that were downloaded beforehand. The goal is to make an article readable offline. This solution is still under development and may be released very soon.
  • Notifications support
    We decided not to implement notifications on PWA. First, it is not yet supported on iOS, second, it was impossible to send only one notification to a user who installed both the native application and PWA. Since Chrome 59, a new getInstalledRelatedApps API is available. We may reconsider our approach.

What’s the status after 3 months?

  • Retain mobile website users
    before: time spent/per page = 37s, time spent/per visit 225s
    after: time spent/per page = 40s (+8%), time spent/per visit 234s (+4%)
    -> The impact of PWA on our traffic was less significant than expected. However this release helped us reduce the bounce rate (-1,7%) and increase article page views (+10%).
  • Improve performances
    tests in slow 3G, before: DOMContentLoaded 11s, Load 54s, requests 192, weight 3.2Mo
    tests in slow 3G, after: DOMContentLoaded <1s, Load 7s, requests 77, weight 1.3Mo
    -> All metrics confirm that from a performance point of view this PWA is a success. However, this is still an area we always want to improve.
  • Offer an offline mode
    -> We completed a first step. Now we need to go further by offering content offline, while making sure the phone memory and user bandwidth are not overloaded, which is quite tricky.
  • Innovate
    -> We reached and even exceeded our target. Indeed PWA allowed us to innovate beyond its initial scope (in native apps and back office)

It may be a bit early to draw conclusions as there is still a lot of work and improvements to make. However our feeling is that the implementation of the PWA allowed us to make a technical leap forward. We see it as a critical first step in supporting our mobile growth.

In terms of traffic, L’Équipe mobile website represents between 3 and 10 millions page views per day. In August 2017 we reached nearly 9 millions unique visitors (Mediametrie).

Read more

Pinterest case study:

PWA for Twitter: