Google complaining about slow Interaction to Next Paint (INP) on Discourse sites

Hi there, first of all I’d like to say that I’m not one to chase after SEO or go out of my way to suit Google’s demands preferences on how my own site should look and work. But it’s worth knowing that Google just sent me an email about my site needing to improve on their new “Core Web Vital metric” that will soon start factoring very heavily into their rankings:

Here’s the report on Discourse Meta, which is a bit worse than my own site for INP (372ms vs 208ms):

Given that Discourse is basically a Javascript web app I image it won’t be easy to improve those metrics. But then again Google appears to be basing its ranking on the no-Javascript version that its web crawlers are seeing despite claiming to be emulating a Moto G Power phone…

…so I don’t really believe or care too much about what their algorithms and rankings determine. But it’s worth a heads-up for devs and site administrators to be aware of.

6 Likes

Hi @rahim123 - improving INP is one of the motivations for switching Discourse’s page navigation animation from a full-page ‘spinner’ to a slider. We only deployed that change to Meta last week, so it’s a little soon for the change to show up in Google’s web vitals survey data.

But rest assured we’re keeping an eye on the data and will look into making further tweaks if needed.

12 Likes

Thanks a lot for the reply. Glad to hear you’re on top of this.

I used Google’s live URL tester https://pagespeed.web.dev, so shouldn’t that already be included in the ranking? And since Google is seeing the no-Javascript version I’m not sure how it takes the spinner vs. slider into account? Doesn’t INP have to do with navigating from one page to another within the same website? In that case I don’t really understand how it gauges that metric for a single URL. Sorry for my ignorance, I’m far from an expert on these minutia relating to page architecture and Google’s latest whims.

1 Like

Yeah, ‘pagespeed insights’ and google’s search crawler fetch the basic-html version of Discourse. So unfortunately these on-demand tools are not too helpful for us.

For search ranking, Google uses real-world data collected from users of Chrome on desktop and Android. They make that data available publicly at Overview of CrUX  |  Chrome UX Report  |  Chrome for Developers. Unfortunately there’s a 1-2 month delay between collection and publication, which is why we need to wait a while before we can see the real-world impact of this new loading slider.

To see Google’s data for your own site (or for Meta), go here and enter the domain: CrUX Dashboard  |  Chrome UX Report  |  Chrome for Developers. Once you’ve loaded the report, there’s a tab for INP on the left hand side. IIRC, Google focusses on the ‘mobile’ data for search ranking, so you’ll need to use the device filter to dig into that.

Mobile data for Meta:

The aim is to get at least 75% ‘good’ - that will mean that the P75 INP value which Google uses for search ranking is less than 200ms.

9 Likes

Wow, never even heard of that. Thanks a lot for the explanation!

3 Likes

As a datapoint, I have been exclusively using the discourse-loading-slider theme component since my site was live. I am still in the “needs improvement” zone

Particularly, it seems the pages that are accessed primarily by anonymous accounts coming from google perform the worst. Could be specific to my forum but thought it was worth sharing

4 Likes

David, it does seem a huge perceived improvement, though I am fond of the old spinner :wink: Can you remind me what the high level technical change of approach here that facilitates that improvement? Has that been documented somewhere?

The improvement to the INP?

With the old spinner, the sequence was

  1. Click link
  2. Ember tears down all DOM and cleans up components from the old route
  3. Spinner rendered to screen
  4. Once network request resolved, render new route to DOM

With the slider, we skip step 2. The slider gets rendered immediately, without needing to wait for the expensive teardown process.

I should clarify here: the main motivation for us switching the default is the improved UX. The INP metric improvement is also nice, but not the primary reason for the change.

5 Likes

Yeah it’s the perception that matters most and not removing the content too soon is a nice touch. Great work!

1 Like

It’s very important to note that INP will only impact site rank in March 2024, so the improvements that we are working on today have time to be iterated upon before it starts affecting Google.

7 Likes

I am quite fond of the old one as well. Is it possible for us to have a theme component (or perhaps a user setting) for the old spinner?

3 Likes

There is a system-wide setting to switch back: page loading indicator

True, but some people do like the new one, and I’d prefer not to mess with their settings.

Also, IIRC, that switch is planned to be removed soon.

2 Likes

Oh, I thought they just recently added it?

True, but see this:

4 Likes

For your own domain data like meta.discourse.org there is always a recent report in Google Search Console hidden inside ‘Experience’ → ‘Core Web Vitals’ → ‘Mobile (Open report)’ and scroll down to ‘INP issue: longer than 200ms (mobile)’

Edit: This is more on the low-probability/high-impact scale. INP only takes p75 into account.

The INP might be influenced by the post ?cooking? procedures (= feature enhancement via JS on loading) of the Matomo core or plugins which do some ‘heavy’ JS tasks having a large ‘render blocking time’.

Especially when the user switches to another thread, there are like 10-20 posts “cooked” at once.

Here its always good to split the tasks for individual posts into separate setTimeouts() to allow the browser to do painting in between the individual tasks and not wait for the whole process to finish.

E.g. something like this:

var initializeSliderSlickItem = function (item) {
  /* do the actual initialization here */
  var $this = $(item);
  […]
};

$('.slider-slick').each(function () {
  var item = this;
  setTimeout(initializeSliderSlickItem, 0, item);
});

Are you sure about that? When going from a topic to another, the next paint will be the loader at the top of the page, that starts right away.

1 Like
Edit: This is more on the low-probability/high-impact scale. INP only takes p75 into account.

… and afterwards the cooking starts. If the user then clicks on something while a Discourse cooking task is running, Google measures INP as the time until next paint. Next paint might appear earliest on finish of the running cooking task.

See web.dev: INP: What is an interaction

Ng0j5yaGYZX9Bm3VQ70c

“The life of an interaction. An input delay occurs until event handlers begin running, which may be caused by factors such as long tasks on the main thread [e.g. “cooking”]. The interaction’s event handlers then run, and a delay occurs before the next frame is presented.”


Google takes the longest paint blocking time into account for INP if there are multiple blocking events “throughout the entire page’s lifecycle”. Lifecycle like:

  1. URL thread “A” opens
  2. spinner shows
  3. cooking posts in thread “A”
  4. Click 1: user clicks link to thread “B”
  5. spinner shows
  6. thread “B” loading
  7. cooking posts in thread “B”
  8. Click 2: user clicks link to thread “C” while thread “B” is still cooking
  9. the running cooking action on thread “B” finishes (<-- counts into INP for Click 2 )
  10. spinner shows
  11. thread “C” loading
  12. cooking posts in thread “C”

Also web.dev: INP: What is an interaction
vNosnKDYgBRnFmEvwm0c

“INP is calculated when the user leaves the page, resulting in a single value that is representative of the page’s overall responsiveness throughout the entire page’s lifecycle.”

Good thing that using the p75 of the metric means that no one needs to really worry about this scenario you painted, and it’s clearly not representative of normal interactions with Discourse.

2 Likes