How to fix slow Interaction to Next Paint (INP) by optimising JavaScript and API Responses

Last updated:

Home » Articles » Web Performance » How to fix slow Interaction to Next Paint (INP) by optimising JavaScript and API Responses

Website performance directly impacts user experience and business outcomes. When users interact with a website and experience delays, they perceive it as sluggish or broken, often leading to frustration and abandonment. This article explores practical solutions for improving Interaction to Next Paint (INP) – a critical metric that measures how quickly your website responds to user inputs.

How to solve the issues

1. Identify and Measure INP Problems

Before making any optimizations, you need to understand where the problems exist:

  • Implement measurement tools: Use the web-vitals JavaScript library to track INP across your website.
  • Set up analytics: Connect your INP data to an analytics system (like ELK, Google Analytics, or similar) to identify the worst-performing pages and interactions.
  • Establish baselines: Document current INP values at the 75th and 95th percentiles to measure improvement.

2. Optimize Event Handlers for Scroll-Triggered Interactions

Scroll events can easily overwhelm the main thread when not properly managed:

// Before: Unoptimized scroll handler
window.addEventListener('scroll', function() {
  // Expensive operations that run on every scroll event
  loadMoreResults();
  updateUI();
});

// After: Debounced scroll handler
let scrollTimeout;
window.addEventListener('scroll', function() {
  clearTimeout(scrollTimeout);
  scrollTimeout = setTimeout(function() {
    // Operations now run less frequently
    loadMoreResults();
    updateUI();
  }, 100); // Adjust timing as needed
});

3. Prioritize Rendering Work

Ensure rendering operations happen at the right time:

// Before: Direct DOM updates
function updateSearchResults(data) {
  // Directly manipulating DOM
  resultsContainer.innerHTML = createResultsHTML(data);
}

// After: Using requestAnimationFrame
function updateSearchResults(data) {
  requestAnimationFrame(() => {
    resultsContainer.innerHTML = createResultsHTML(data);
  });
}

4. Optimize Lazy Loading Strategies

Improve how additional content loads as users interact:

  • Trigger earlier: Load the next batch of content when the user reaches the second-to-last item instead of waiting until they reach the very end.
  • Reduce batch size: Fetch smaller batches of data (e.g., 10 items instead of 30) to reduce processing time.
function setupLazyLoading() {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        fetchNextBatch(10); // Smaller batch size
        observer.unobserve(entry.target);
        setupNextTrigger();
      }
    });
  });
  
  // Observe the second-to-last item instead of the last
  const items = document.querySelectorAll('.result-item');
  if (items.length >= 2) {
    observer.observe(items[items.length - 2]);
  }
}

5. Manage State Updates Efficiently

Prevent excessive re-renders when users interact with form elements:

// Before: Every keystroke triggers a state update
inputField.addEventListener('input', (e) => {
  // Updates global state and triggers re-renders
  store.dispatch(updateSearchQuery(e.target.value));
});

// After: Local state management with deferred updates
let localInputValue = '';
inputField.addEventListener('input', (e) => {
  // Update local value without triggering re-renders
  localInputValue = e.target.value;
});

inputField.addEventListener('blur', () => {
  // Only update global state when focus leaves the field
  store.dispatch(updateSearchQuery(localInputValue));
});

6. Optimize API Response Size

Reduce the amount of data transferred from your API:

  • Trim payload size: Remove unnecessary fields from API responses.
  • Implement pagination: Return only the data needed for the current view.
  • Use compression: Ensure your server compresses responses (gzip/Brotli).

7. Monitor and Iterate

After implementing changes:

  • Continue measuring: Keep tracking INP to verify improvements.
  • Segment data: Analyze performance across different devices and connection speeds.
  • Iterative improvements: Make incremental changes and measure their impact.

Conclusion

The key strategies include debouncing event handlers, prioritising rendering work, optimising lazy loading, managing state updates efficiently, and reducing API payload sizes. Each of these techniques helps reduce main thread blocking and ensures your website responds quickly to user interactions.

Wave

Enjoy our articles? Join our free list and get more.

Sign Up

Book Discovery Call