Page MenuHomePhabricator

Serve low-res images by default to users on slow or metered mobile connections
Closed, ResolvedPublic

Description

  • On slow mobile connections, the default quality setting for thumbnails produces thumbnails which are impractically large. We should optimize for speedy delivery rather by serving low-res thumbnails by default.
  • We use srcset to serve high DPI images to mobile devices that have a display with a high pixel density. However, that is not the only factor that should be relevant; equally (or more) important is the user's connection speed. We should not serve high DPI images to users on a 2G connection by default, even if the device is capable of displaying them.

Payload size of [[en:Barack Obama]] with and without proposed modifications:

VariantPayload size
Current version (unmodified)1,801 KB
No srcset; qlow JPEGs756 KB

Plan

  • Use historic NavigationTiming data to assign a speed rating of "slow" or "fast" to each country / region pair.
  • Have Varnish set a NetSpeed=slow or NetSpeed=fast cookie based on geolocation.
  • Vary the cache on NetSpeed cookie. (Or rather: in vcl_hash, update the hash if req.http.Cookie ~ "(^|;\s*)NetSpeed=slow").
  • Have MobileFrontend handle NetSpeed=slow requests differently, by omitting the srcset attribute and rewriting JPEG URLs to use the qlow variant.

A/C

  • In mobile web srcset should not be present
  • In apps srcset should be present in API response
  • Change default images served to mobile web users to be low-res images
  • Update the option in SPecial:MobileOptions from data-saving mode to be 'hi-res mode' (invert behaviour)

Related Objects

StatusSubtypeAssignedTask
OpenReleaseNone
OpenNone
OpenNone
OpenNone
OpenFeatureNone
OpenNone
Resolveddr0ptp4kt
DuplicateNone
Duplicate Jhernandez
Duplicatedr0ptp4kt
DeclinedNone
ResolvedJdlrobson
DeclinedNone
InvalidNone
DeclinedNone
Resolvedori
DeclinedNone
Declinedori

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Interlaced thumbnails might be of interest (for slow connections; does not help with metered).

Made a separate task out of this after talking about it with Volker: T120032

Change 256360 had a related patch set uploaded (by Ori.livneh):
[WIP] Omit srcset attributes when NetSpeed cookie is present and set to 'low'

https://gerrit.wikimedia.org/r/256360

I find discriminating the content we serve based on geolocation concerning.

I find discriminating the content we serve based on geolocation concerning.

Well, sure, if you put it like that, it sounds pretty ominous. But the only modification I'm proposing is that we tune down the default image resolution. Does that seem problematic? And if so, what do you suggest we do instead?

I think "geolocation" is somewhat misleading here; it's more like an IP -> network type database. Not much different from showing low-res content for 2G, except whether the connection is 2G is guessed from the IP address (initially, anyway).

I truly believe we should be doing this for all users and enhancing on demand via JavaScript for mobile. BBC news does this.

I don't see this as discriminatory as it improves experience for everyone and it actually gives someone with a 2g connection the ability to view our content (remember high resolution blocks first paint).

I find discriminating the content we serve based on geolocation concerning.

Well, sure, if you put it like that, it sounds pretty ominous. But the only modification I'm proposing is that we tune down the default image resolution. Does that seem problematic? And if so, what do you suggest we do instead?

navigator.connection.downlinkMax will be in Chrome soon, that might be a reasonable alternative to geolocation.

Gabriel has been plugging client hints, but I was reading the Chrome documentation, and it seems they do not plan to add downlink speed to their implementation, despite it being in the spec. See the FAQ "What about <insert my favorite hint>?"

navigator.connection.downlinkMax will be in Chrome soon, that might be a reasonable alternative to geolocation.

There are a number of ways we could gauge network performance in JavaScript, but I think it's important to make an educated guess for the first page-load in a browsing session, too.

navigator.connection.downlinkMax will be in Chrome soon, that might be a reasonable alternative to geolocation.

I have a patch for that (the API has been enabled for Chrome on Android for a while); it will be nice for statistics but problematic for triggering a "slow connection mode". downlinkMax is exactly that: the theoretical maximum download speed. For a typical cable connection, that's the speed you get when you are the only person using that cable; the actual speed tends to be a fraction of it. I'm not sure about mobile where it is theoretically possible for the client to know the actual bandwidth that has been allotted to it but I don't know if that information is exposed. (IIRC the spec handwaves it away and leaves it to the implementation what "maximum speed" means and whether e.g. distance from the base tower should be taken into account.)

Just measuring the speed of the first page load and updating the cookie based on that might be a more realistic option.

I truly believe we should be doing this for all users and enhancing on demand via JavaScript for mobile. BBC news does this.

Wouldn't that result in fast clients downloading the images twice?

An interesting option I have read about is to use interlaced images and use HTTP/2 multiplexing and dynamic priorities to make sure the first few segment of each image arrives first, so that instead of displaying them in order, each image is displayed at an acceptable level of quality first, then each image is refined. No idea if this is actually possible or a "HTTP/2 might make this possible one day" thing. (Also, if most images are below the fold this might be actually counterproductive. But I believe we plan to load those images by Javascript anyway.)

@Tgr About progressive/interlaced: There's been different views of what's best. I think the old best practice was to serve progressive for images larger than 10kb but there was a study (http://www.webperformancetoday.com/2014/09/17/progressive-image-rendering-good-evil/) that showed that people prefer images that appear in one go instead because they make people happier (yeah, hehe).

When, as with the Progressive JPEG method, image rendition is a two-stage process in which an initially coarse image snaps into sharp focus, cognitive fluency is inhibited and the brain has to work slightly harder to make sense of what is being displayed.

I wouldn't say it's the 100% truth but its a interesting factor.

@Tgr You can read more about BBC's approach at https://github.com/BBC-News/Imager.js/

I might be misunderstanding that completely but it looks like it wouldn't load the images at all without Javascript which is a non-starter IMO.

Also if you load the images for fast clients from Javascript, you lose any advantages from speculative parsing. That's a nontrivial difference.

@Tgr About progressive/interlaced: There's been different views of what's best. I think the old best practice was to serve progressive for images larger than 10kb but there was a study (http://www.webperformancetoday.com/2014/09/17/progressive-image-rendering-good-evil/) that showed that people prefer images that appear in one go instead because they make people happier (yeah, hehe).

Yeah, that article is interesting but also smells horribly of a marketing hack; it's easy to manipulate small studies to say whatever the experimenter wants them to say. Most comments I have read about it came to the same conclusion.

Anyway let's continue that line of discussion in T120032; I'll play around a bit with interlacing if I find the time.

@Tgr About progressive/interlaced: There's been different views of what's

best. I think the old best practice was to serve progressive for images
larger than 10kb but there was a study (
http://www.webperformancetoday.com/2014/09/17/progressive-image-rendering-good-evil/)
that showed that people prefer images that appear in one go instead because
they make people happier (yeah, hehe).

This study also required that participants be on their "own webcam-enabled
computers." They're probably not on 2G connections, so their preferences
could be hugely different.

I find discriminating the content we serve based on geolocation concerning.

Well, sure, if you put it like that, it sounds pretty ominous. But the only modification I'm proposing is that we tune down the default image resolution. Does that seem problematic? And if so, what do you suggest we do instead?

I'm just not convinced we should do this at all.

  1. It definitely sounds very ominous, even if we're just doing this to improve user experience. Tracking users to give them tailored ads is also claimed to improve user experience ;) You could say that only loading the beginning of an article, or only loading the wikitext editor, on low-speed connections would also improve user experience. Do that a few times and it turns out that people, say, here in Poland are getting a completely different Wikipedia than Americans. I think we should avoid doing this on principle.
  2. I'm pretty sure that the state of available data and APIs just is not good enough to let us always make the correct decision (or even to make the correct decision most of the time). We've been talking about connection speed, which I guess we can discover well enough most of the time (but I don't think we can tell apart high latency from low bandwidth?), but we definitely can't tell whether a connection has a low data cap.

If you're set on going this way, I suggest that the least you could do is add an opt-out. A checkbox somewhere saying "Always serve me high quality content, regardless of my connection", or something. Adding such a user preference, and tweaking the content based on it, might be a good idea whether or not we do detection.

I don't know about other operating systems, but Windows these days lets you mark connections as metered (and uses this to decide whether to download updates automatically, and such). Maybe the idea catches on in a few years and we'll actually be able to do what you want based on correct data that the user themself can control.

I suggest that the least you could do is add an opt-out. A checkbox somewhere saying "Always serve me high quality content, regardless of my connection", or something. Adding such a user preference, and tweaking the content based on it, might be a good idea whether or not we do detection.

Yes, of course. Since we'd be splitting the cache for anons based on this cookie, it can even be an anon preference.

I don't know about other operating systems, but Windows these days lets you mark connections as metered (and uses this to decide whether to download updates automatically, and such). Maybe the idea catches on in a few years and we'll actually be able to do what you want based on correct data that the user themself can control.

That property was part of the first W3C draft of the Network Information API but has been dropped.

Attached CSV file contains 2.7m samples of page load times on the mobile version of English Wikipedia, taken between September 2, 2015 and December 3, 2015.

I restricted the query to English Wikipedia because page load performance varies by wiki (due to differences in site JS / CSS, gadgets, and article size), and the geographical distribution of English Wikipedia traffic is broadest.

Each line contains three comma-separated values: a two-character ISO 3166-1 country code, a two-character ISO 3166-2 region code, and total page load time in milliseconds. The region field may also be an empty string, indicating that the IP could not be geolocated to a specific region.

The set of country and region codes has some MaxMind-specific extensions (like 'A1' for anonymous proxy). The full set is provided here:

The query I ran to select the data is provided below:

SELECT event_originCountry, 
       event_originRegion, 
       event_loadEventEnd 
FROM   NavigationTiming_13317958 
WHERE  event_mobileMode IS NOT NULL 
       AND event_originCountry IS NOT NULL 
       AND event_originCountry != '' 
       AND event_loadEventEnd IS NOT NULL 
       AND wiki = 'enwiki';

Change 256360 merged by jenkins-bot:
Vary HTML output by NetSpeed designation

https://gerrit.wikimedia.org/r/256360

Change 257681 had a related patch set uploaded (by Ori.livneh):
Vary HTML output by NetSpeed designation

https://gerrit.wikimedia.org/r/257681

@dr0ptp4kt, actually i think it might - producing links like xxx-qlow-qlow. I will need to test it though. I wouldn't want images on all wikis disappearing for all of zero.

Change 257681 merged by jenkins-bot:
Vary HTML output by NetSpeed designation

https://gerrit.wikimedia.org/r/257681

Ok, double checked - the "shrinkImg" setting is enabled on about 10 partners. We can either disable all these partners to use regular image quality settings, or we could make that setting automatically set the "NetSpeed: B" cookie. Should we look at how a user can disable this feature?

@Yurik I'd prefer if we could hold off on using the net speed cookie. The plan here is to run a controlled A/B test to collect data around the impact of this change and setting it will disrupt those results. Thoughts @ori ?

@Jdlrobson, that's fine, but i suspect that if we enable NetSpeed:B on any zero partner with shrinkImg enabled, their image URLs would be broken.

We're not enabling the cookie for anyone just yet.

@dr0ptp4kt would you be able to make a varnish change (I don't know anyone else familiar with this) to set the NetSpeed cookie to 'B' for 5% of users via Varnish and 'A' for 5% of users (the other 90% will not be bucketed and no cookie will be set)

This should allow us to see the impact of disabling srcset. @ori is working on a patch to send the value of NetSpeed cookie into NavigationTiming API and then it should be trivial to add a graph to the dashboard comparing the median of A vs B.

@ori please correct me if any of the above is inaccurate.

@Jdlrobson: I don't think we need an A/B test this. Having some WebPageTest runs with and without the cookie should be enough.

ori renamed this task from Serve lo-res images by default to users on slow or metered mobile connections to Serve low-res images by default to users on slow or metered mobile connections.Dec 9 2015, 1:06 AM

Test runs from Chrome on Android with cache disabled, throttling preset "Regular 2G", i.e. 250 kbit/s, 300ms RTT:

  • No cookie
    • Waterfall chart
    • Total compressed size 1.2 MB
    • CSS received at 2.66s
    • DOM ready: 38.76s
    • onload: 43.47s
  • NetSpeed=B
    • Waterfall chart
    • Total compressed size 626 KB
    • CSS received at 3.15s
    • DOM ready: 22.11s
    • onload: 26.59s

Also here's a quality comparison. qlow really does mean low.

Is there any reason we wouldn't make this the default for all users (but configurable via settings) and use JS to upgrade them? The image qualities that Tim posted are blurry but they are useful and get across the purpose of the image and their relation to the article... I'd argue perfectly acceptable for a first paint on mobile.

I imagine 3 modes:

  1. low quality (current net speed B)
  2. Optimal (net speed B with JS to enhance images when they are scrolled into view)
  3. high quality (current net speed A) surfaced on https://en.m.wikipedia.org/wiki/Special:MobileOptions

I imagine making the 2nd mode the default would satisfy a lot of people. With good JS it would be hardly noticeable on a fast connection and appreciated on a slower one.

Like @matmarex I worry about an approach that discriminates based on location. I get 2G in my mother's house in the UK. Applying this to everyone and allowing the ability to override seems like a cheaper more impactful option... but that's just my 2 cents.

@ori previously asked reading to take over this but I notice it has moved up to 'Next-up' on the performance team workboard. It would be good to have a better understanding of ownership of this problem - I would like reading to make some changes here for January but I don't want to step on toes....

Is there any reason we wouldn't make this the default for all users (but configurable via settings) and use JS to upgrade them? The image qualities that Tim posted are blurry but they are useful and get across the purpose of the image and their relation to the article... I'd argue perfectly acceptable for a first paint on mobile.

This would deteriorate user experience, slow-down page load times, delay the "settle" time for page rendering (the duration during which the rendering changes before it "settles" will be even longer), and it will consume more bandwidth data for users. Adding more JavaScript is rarely, if ever, the right solution. JavaScript also kicks in relatively late after first paint, so it would be quite noticeable for users even on fast connections.

If we want a quick early rendering for images, I'd recommend we look into something like https://css-tricks.com/the-blur-up-technique-for-loading-background-images/ as popularised by Facebook. Which we could trigger early before first paint with an inline class added, similar to what we do with client-js right now.

@ori previously asked reading to take over this but I notice it has moved up to 'Next-up' on the performance team workboard. It would be good to have a better understanding of ownership of this problem - I would like reading to make some changes here for January but I don't want to step on toes....

I think the performance team is in a better position to actually do the bucketing at the Varnish layer, though we need help from @Tbayer to analyze the data. What are you planning on doing in January?

Is there any reason we wouldn't make this the default for all users (but configurable via settings) and use JS to upgrade them? The image qualities that Tim posted are blurry but they are useful and get across the purpose of the image and their relation to the article... I'd argue perfectly acceptable for a first paint on mobile.

This would deteriorate user experience, slow-down page load times, delay the "settle" time for page rendering (the duration during which the rendering changes before it "settles" will be even longer), and it will consume more bandwidth data for users. Adding more JavaScript is rarely, if ever, the right solution. JavaScript also kicks in relatively late after first paint, so it would be quite noticeable for users even on fast connections.

I'm a little confused since...

If we want a quick early rendering for images, I'd recommend we look into something like https://css-tricks.com/the-blur-up-technique-for-loading-background-images/ as popularised by Facebook. Which we could trigger early before first paint with an inline class added, similar to what we do with client-js right now.

I guess this is what I am asking. Is exploring this route worthwhile? There is also http://responsivenews.co.uk/post/58244240772/imagerjs that BBC use.

I haven't thought too much about implementation details but why wouldn't we optimise for early rendering of images/earlier first paint?

What are you planning on doing in January?

@ori I guess it's still not clear to me how we set this cookie. The geo way seems flawed imo and you would at least need to build a way to allow a user to opt out if it. Seems like work the reading team could help for.

@ori I guess it's still not clear to me how we set this cookie. The geo way seems flawed imo

Sending very large, high-resolution images to clients without regard for the cost (in time and money) is pretty bad.

Using JavaScript to control how and when images are loaded could work very well, especially since it provides a means for not loading images below-the-fold at all, unless the user scrolls down. So I am happy to see the reading team move in this direction. But I know from experience (and you do too) that getting a JavaScript image loader for MediaWiki to the point where we can deploy it to production is going to take a lot of time and a lot of very careful testing to ensure we get good results across all major browsers. There is also a nonzero chance that we will reach the conclusion that this approach is not the right one.

The other option on the table is to unconditionally disable responsive images (@brion provided a configuration variable, $wgResponsiveImages, for that purpose), or to disable responsive images by default, and require opt-in. I think that this is a non-starter, because we have been serving responsive images since 2012 (966cda2f80), and turning them off would constitute a regression for a lot of users.

Splitting the mobile cache into a high-bandwidth and a low-bandwidth variant and using past performance data and geolocation to choose a good default experience seems to me like a good way to attack this problem, because it is straightforward to implement, and because it will improve user experience substantially where it is currently poorest, and because it makes it easy to provide a means for readers to switch variants if we picked the wrong default. I think that this is the right solution for now, but I don't think it will be the last word on loading images, so I think continuing to explore other solutions (as you are doing) is worthwhile and not in conflict with what I am suggesting.

If you want control over the weight and timing of image loading, the only way to do it effectively is going to be to write our own client-side JS logic...

Via markup all we can control is the image size with limited controls based on display density or size, neither of which gives us info about network speed... Sounds like there are IP-based lookups to approximate network (for server-side segmentation of the markup) but that doesn't guarantee much about speed as the devices and plans may vary within a network...

Of course you need a non-JS fallback behavior that's sane. That can be done with ugly <script>/<noscript> pairs or just by having the raw markup specify something were willing to preload and willing to show to non JS readers.

@ori cache split does sound easier to implement though, so probably worth trying if the IP lookup is reasonably workable.

Lowering both the JPEG quality and reducing the pixel ratio to 1.0 might be a bit too much and certainly will be hard to apply universally to traffic without degrading user experience. At least for desktop and tablet users we should avoid it. And even on mobile it might be tough.

Detecting zoom and pan onto an image with JavaScript is possible, but I don't think that's the right direction for this.

Providing user preferences is imho almost without meaning. Users, to a first approximation, do not want and will not use preferences. It doesn't justify the degraded user experience. (By preference I mean an obscure option that casual users cannot realistically discover.)

A lightweight overlay banner communicating that we detected a slow or expensive connection and enabled NetSpeed=B mode could work. The banner button would e.g. set a NetSpeed=A cookie. That seems imho the only adequate way to go about it. But such a banner brings a relatively high UX cost. Something of a last resort to avoid if possible.

My proposal would be to:

  • First fix T122242, which might save 15-20% in size across the board for all users.
  • For NetSpeed=B users, only do one of (low quality) or (1.0 pixel ratio). Which would reduce the visual impact.

Also keep in mind that no matter how much we try to squeeze our subresources (JS, CSS, Images) the main overhead seems to be the HTML size. And time it takes a browser to parse and render all elements, and fire off subresource requests for each image. I suspect that working on serving less sections by default (and, by extend, less images) will be a more worthwhile effort in both bandwidth, load time, and user experience.

Lowering both the JPEG quality and reducing the pixel ratio to 1.0 might be a bit too much and certainly will be hard to apply universally to traffic without degrading user experience. At least for desktop and tablet users we should avoid it. And even on mobile it might be tough.

Detecting zoom and pan onto an image with JavaScript is possible, but I don't think that's the right direction for this.

Providing user preferences is imho almost without meaning. Users, to a first approximation, do not want and will not use preferences. It doesn't justify the degraded user experience. (By preference I mean an obscure option that casual users cannot realistically discover.)

A lightweight overlay banner communicating that we detected a slow or expensive connection and enabled NetSpeed=B mode could work. The banner button would e.g. set a NetSpeed=A cookie. That seems imho the only adequate way to go about it. But such a banner brings a relatively high UX cost. Something of a last resort to avoid if possible.

My proposal would be to:

  • First fix T122242, which might save 15-20% in size across the board for all users.
  • For NetSpeed=B users, only do one of (low quality) or (1.0 pixel ratio). Which would reduce the visual impact.

Also keep in mind that no matter how much we try to squeeze our subresources (JS, CSS, Images) the main overhead seems to be the HTML size.

To add weight to this I ran some tests on the Barack Obama article in 2G rendering in different conditions without any stylesheets/JS/chrome.

https://www.mediawiki.org/wiki/Reading/Web/Projects/Barack_Obama_in_under_15_seconds_on_2G#Experiments_with_article_composition_on_2G

Change 270793 had a related patch set uploaded (by Ori.livneh):
Don't serve HiDPI thumbs on mobile

https://gerrit.wikimedia.org/r/270793

Jdlrobson added a subscriber: Nirzar.

Jon to setup a meeting with @Nirzar @dr0ptp4kt about design concerns around this

Change 270793 merged by jenkins-bot:
Don't serve HiDPI thumbs on mobile web

https://gerrit.wikimedia.org/r/270793

@ori can you update/close this task related to the changes we've done and changes you feel need to be done in future?
Note low-res images using qlow is captured in T120875

@Krinkle talked about the Save-Data client hint request header that could be an alternative for the user to choose low quality images. Hope more browsers pick it up.

Okay to close this out, now that hidpi is removed on mobile web?