DevLog - Web Vitals, P99, Journal Updates

Lessons on measuring and improving Interaction to Next Paint (INP), plus what's new in Tomatillo Timer

Erik
Erik
October 8, 2026 • 2 min read

This week I did a deep dive on web vitals, P75-99, field metrics, and synthetic testing in Chrome DevTools. I also published a few performance and quality of life updates to the Journal feature of Tomatillo Timer.

Here’s what I learned.

Interaction to Next Paint

INP is Interaction to Next Paint. It is a core web performance metric that measures how fast a website responds to user actions. For example, a user focuses a text area and presses a key on the keyboard. If the letter takes 200ms to display, we would say the INP is 200ms.

Core web vitals, like INP, are usually categorized into percentiles like P75 or P99. For example, let’s say our INP for P75 is 200ms.

  • 75% of users experience a peak INP of 200ms or faster.
  • The remaining 25% of users experience a peak INP of 200ms or slower.
Chrome UX Report labels 200ms or less as "good" for P75 field metrics. Analytics companies like PostHog claim a good INP score is 100ms or lower. Personally, I prefer the PostHog standard, as I think an app feels somewhat laggy at 200ms.

Here is a look at a particularly bad P99 INP I had reported on my web vitals. This represents the 1% of slowest users of my application.

INP (ms) - daily

Local Testing

Contrary to the graph, when I test INP locally on my MacBook Pro, I see a peak INP of around 64ms (potentially 20x faster than some of my P99 data points).

We can simulate CPU throttling using the performance tab of the Chrome DevTools. This can be a great way to find potentially laggy parts of your application. However, I found that this was a pretty volatile way to measure performance. A lot of factors can affect INP at any given time.

To improve INP, optimize JavaScript performance, reduce unnecessary layout changes, and ensure smooth animations.

-PostHog Docs

Some changes I made that had a positive impact on my INP:

  • Optimizing code that was creating many unnecessary objects, and excessively reading/writing to storage. Note, it may take a large data set or high throttle for this to start to make a difference.
  • Removing backdrop-filter blurs. These can be expensive when animating. In my case I kept the blur effect but replaced it with filter: blur and a pseudo-element instead.

Tomatillo Updates

For Tomatillo Timer users, an update on the journal feature:

  • Journal is now more performant on larger data sets and slower machines / mobile.
  • Journals now loads when open, improving app start times, and reducing likelihood of stale data.
  • Journal can now render images from URLs
    • [title](image_url) or copy paste an image from the internet
  • Journal now maintains its scroll and cursor position.
  • Upcoming feature: Multiple journals per user.

And some quality of life improvements:

  • Improved load times by lazy loading unseen components and sub-setting fonts.
  • Config widget lazy loads YouTube thumbnails and remembers your last tab.
  • Minor visual updates to older components that needed some love.

Comments

Join the discussion for this post on Bluesky or Discord
Discuss on Bluesky
Discuss on Discord *
* Members of the discord can use the link directly, otherwise use this invite