How to Identify and Fix Long Tasks in Chrome DevTools

How to Identify and Fix Long Tasks in Chrome DevTools

How to Identify and Fix Long Tasks in Chrome DevTools- Updated 2026

Key Takeaway: A long task is any JavaScript operation that runs for more than 50ms on the browser's main thread. During a long task the browser cannot respond to clicks, taps, or keypresses — directly causing poor INP scores. Chrome DevTools Performance panel is the most powerful tool for finding exactly which code is creating long tasks and how long each one runs. This guide walks through the complete process: recording, reading the flame chart, identifying the culprit code, and applying the right fix.

Your INP score is failing. PageSpeed Insights says "Avoid long main-thread tasks." But which tasks? Which code? Which interactions are slowest?

That is exactly what Chrome DevTools Performance panel tells you — if you know how to read it.

Most developers open the Performance panel, see a wall of coloured bars, and close it again. The flame chart looks intimidating. The terminology is unfamiliar. It is not obvious where to start.

This guide removes all of that friction. By the end you will know how to record a performance trace, read the flame chart, find the specific function causing your long tasks, and apply the correct fix — whether that is yielding the main thread, splitting a bundle, or deferring a third-party script.

If you want the full context on why long tasks matter for INP specifically, start with INP vs FID: what changed and why it matters for SEO. If you already understand INP and want to go straight to fixing the JavaScript causing your long tasks, see how to reduce JavaScript execution time. This article covers the diagnostic step in between, finding exactly where the problem is.

What is a long task?

A long task is any continuous block of work on the browser's main thread that takes longer than 50ms to complete.

The 50ms threshold comes from the RAIL performance model. To feel instantaneous, a visual response needs to happen within 100ms of a user interaction. The browser needs roughly 50ms to render a frame after JavaScript finishes running. That leaves 50ms for JavaScript execution. Any task longer than 50ms eats into the rendering budget — and tasks significantly longer than 50ms block user interactions entirely.

During a long task, the browser cannot:

  • Process click or tap events
  • Process keyboard input
  • Render new frames
  • Run other JavaScript callbacks

The user sees a frozen or unresponsive page. Google records the delay as part of the INP measurement.

Long Task Duration User Perception INP Impact
50ms – 100ms Slight sluggishness Minor
100ms – 200ms Noticeable delay Significant
200ms – 500ms Page feels slow INP fails (Needs improvement)
500ms+ Page feels broken INP fails (Poor)

Setting up Chrome DevTools for performance analysis

Before recording, configure DevTools to give you the most useful data:

Step 1: Open DevTools and go to the Performance panel

Press F12 (Windows/Linux) or Cmd+Option+I (Mac) to open DevTools. Click the Performance tab.

Step 2: Enable CPU throttling

This is the most important setup step. Your development machine has a much faster CPU than the average mobile device your users are on. Without throttling, long tasks that affect real users may not appear in your recording at all.

Click the gear icon (⚙) in the Performance panel toolbar. Set CPU throttling to:

  • 4x slowdown — simulates a mid-range Android device (recommended starting point)
  • 6x slowdown — simulates a budget Android device (use for mobile-heavy audiences)

Step 3: Enable network throttling (optional but recommended)

Set network throttling to Fast 3G or Slow 4G to simulate realistic mobile conditions. This affects resource loading times — important for seeing how JavaScript loading interacts with your long tasks.

Step 4: Enable Web Vitals

In the Performance panel gear settings, check "Web Vitals". This adds an INP timeline to your recording — showing exactly when each interaction occurred and how long it took to respond.

Step 5: Open an incognito window

Run your performance recordings in an incognito window. This prevents browser extensions from adding their own JavaScript to your recordings and skewing the results.

Recording a performance trace

There are two types of recordings you need to make: a page load recording (for LCP-related long tasks) and an interaction recording (for INP-related long tasks).

Recording type 1: Page load trace

For LCP and loading-phase long tasks:

  1. In the Performance panel, click the reload button (circular arrow icon) — not the record button
  2. DevTools reloads the page and automatically records the entire load sequence
  3. Stop the recording after the page finishes loading (usually 5–10 seconds)
  4. DevTools displays the full load trace

Recording type 2: Interaction trace (most important for INP)

For INP-related long tasks on specific interactions:

  1. Click the record button (circle icon) to start recording
  2. Perform the specific interaction you want to analyse — click a filter button, open a dropdown, submit a form, use a search box
  3. Wait 1–2 seconds after the interaction completes
  4. Click Stop
  5. DevTools displays the interaction trace

Pro tip: Record one interaction at a time. Recording 10 interactions in one session makes the flame chart extremely cluttered and hard to analyse. Record, analyse, fix, record again.

Reading the Performance panel flame chart

The flame chart is the main view in the Performance panel. It looks complex, but it follows a consistent structure once you understand the layers.

The layers from top to bottom

Network — shows resource loading (HTML, CSS, JavaScript, images). Blue bars are HTML, purple are CSS, yellow are JavaScript, green are images.

Frames — shows rendered frames as grey bars. Gaps between frames indicate dropped frames (jank).

Web Vitals — (if enabled) shows LCP, INP, and CLS markers as vertical lines with labels.

Main — the most important section. Shows everything happening on the main thread — JavaScript execution, style calculation, layout, and painting. This is where long tasks live.

Compositor — shows GPU-composited work (CSS transforms, opacity animations).

Reading the Main thread section

The Main thread section is a flame chart — a stack of coloured bars where:

  • Width = duration (wider = longer)
  • Height/stacking = call stack (bars below are functions called by bars above)
  • Colour = type of work:
    • Yellow = JavaScript execution
    • Purple = style recalculation and layout
    • Green = painting
    • Grey = other browser work

Long tasks are marked with a red triangle in the top-right corner of the taskbar. This is your primary visual signal — find the red triangles, and those are your long tasks.

Zooming and navigating

  • Scroll — zoom in/out on the timeline
  • Click and drag — pan left/right
  • W/A/S/D keys — zoom in (W), zoom out (S), pan left (A), pan right (D)
  • Click a bar — select it and see details in the Summary panel below

Zoom in tightly on a long task to see its full call stack. The top bar is the task itself. The bars below show which functions were called, which functions they called, and so on down to the specific line of code causing the work.

Identifying long tasks step by step

Step 1: Find the red triangles

After recording, scroll through the Main thread section and look for bars with red triangles in their top-right corners. These are tasks over 50ms.

If you recorded an interaction trace, look for the long tasks that occur immediately after your interaction event — these are the ones causing your INP delay.

Step 2: Check the task duration

Click a red-triangle bar. In the Summary tab at the bottom of DevTools, you will see:

  • Total time — how long the task ran
  • Self time — time spent in this specific function (not including called functions)
  • Activity — breakdown of what type of work was done

Any task over 200ms is an urgent INP fix target. Tasks between 50ms and 200ms are worth addressing, but less critical.

Step 3: Find the specific function

Zoom in on the long task. The flame chart shows a stack of bars — each bar is a function call. The deepest bar (lowest in the stack, the one with no bars below it) is where the actual work is happening.

Look at the function names in the bars. You will see:

  • Your own code — function names from your codebase (e.g., filterProducts, handleClick, renderResults)
  • Framework code — React internals (e.g., performSyncWorkOnRoot, reconcileChildren), Vue internals, etc.
  • Third-party code — scripts from external domains (e.g., gtm.js, fbevents.js, widget.js)
  • Anonymous functions — shown as (anonymous) — common in minified code

Step 4: Click through to the source

Click on any function bar in the flame chart. In the Summary panel, click the function name link — it opens the Sources panel and highlights the exact line of code.

For minified production code, you will see minified variable names. Enable source maps to see the original code:

  1. In the DevTools Sources panel, click the {} icon (Pretty-print) to format minified code
  2. If source maps are configured, DevTools automatically shows the original source
  3. For React apps, install the React DevTools browser extension — it adds React component names to the flame chart

Step 5: Identify the pattern

Once you have found the function, categorise what kind of long task it is:

Pattern A: Your own synchronous data processing. Your code is doing expensive work synchronously — sorting, filtering, transforming large arrays without yielding.

Fix: Break up the work with scheduler.yield()

Pattern B: React/framework re-render. The flame chart shows React internals (performSyncWorkOnRoot, reconcileChildren) taking 200ms+.

Fix: Add React. memo, useCallback, useMemo, or useTransition

Pattern C: Third-party script. The long task originates from an external script domain — gtm.js, fbevents.js, a chat widget, and an analytics platform.

Fix: Defer the script, delay the load until interaction, or move to Partytown

Pattern D: DOM manipulation. The flame chart shows large purple bars (style recalculation and layout) following JavaScript execution — indicating your JavaScript is triggering expensive layout recalculations.

Fix: Batch DOM reads and writes, reduce DOM size, avoid layout thrashing

The interaction origin trace — finding INP culprits precisely

For INP debugging specifically, Chrome DevTools has a dedicated workflow for tracing the exact source of an INP delay.

Using the INP marker in Web Vitals

With Web Vitals enabled in the Performance panel, each interaction you perform during recording shows as a vertical marker labelled with its INP value. Click an INP marker to jump directly to the main thread activity during that interaction.

The interaction breaks down into three phases:

Input delay — time from the interaction event firing to when the event handler starts running. Long input delay usually means the main thread was busy with another task when the user clicked.

Processing time — time spent running the event handler and all the JavaScript it triggers. This is where most INP time is spent.

Presentation delay — time from when JavaScript finishes to when the browser paints the visual response. A long presentation delay usually means expensive style recalculation or layout triggered by JavaScript.

Each phase shows separately in the DevTools timeline. Knowing which phase is longest tells you exactly which fix to apply:

Longest Phase Root Cause Fix
Input delay The main thread is busy during the interaction time Break up background long tasks, defer third-party scripts
Processing time The event handler is doing too much work Yield within event handler, optimise re-renders
Presentation delay Expensive style recalculation after JS Reduce DOM size, avoid layout thrashing, batch DOM writes

Practical examples: diagnosing real INP failures

Example 1: Filter button with 450ms INP

Scenario: An e-commerce category page. Clicking the "Under $50" price filter takes 450ms to visually update.

Recording: Click record → click the filter button → stop.

What you see in the flame chart:

  • A taskbar 450ms wide with a red triangle
  • Inside the task: handleFilterClickfilterProductsArray.filtersortResultsArray.sort
  • Below that: renderProductGridupdateDOM → large purple style recalculation block

Diagnosis: The filter function is synchronously filtering and sorting 2,000 products, then triggering a full DOM update and style recalculation in one uninterrupted task.

Fix:

javascript
// Before — synchronous 450ms task
function handleFilterClick(filter) {
  const filtered = products.filter(p => matchesFilter(p, filter));
  const sorted = filtered.sort((a, b) => a.price - b.price);
  renderProductGrid(sorted); // triggers full DOM update
}

// After — yielded to stay under 50ms per chunk
async function handleFilterClick(filter) {
  const filtered = [];

  // Filter in chunks, yielding between each
  for (let i = 0; i < products.length; i += 100) {
    const chunk = products.slice(i, i + 1A00);
    filtered.push(...chunk.filter(p => matchesFilter(p, filter)));
    await scheduler.yield();
  }

  // Sort (usually fast enough to not need yielding)
  filtered.sort((a, b) => a.price - b.price);

  // Schedule render as non-urgent transition
  startTransition(() => renderProductGrid(filtered));
}

Example 2: Add to Cart button with 600ms INP

Scenario: A Shopify product page. Clicking Add to Cart takes 600ms to show the cart update.

Recording: Click record → click Add to Cart → stop.

What you see in the flame chart:

  • Taskbar 600ms wide
  • Inside: handleAddToCart → three separate long tasks from third-party scripts: klaviyo.trackEvent, fbq('track'), gtm push
  • Each third-party event fires synchronously in sequence

Diagnosis: The Add to Cart event handler is firing three synchronous third-party tracking events. Each one takes 150–200ms. They run in sequence — total: 600ms.

Fix:

javascript
// Before — synchronous third-party calls blocking interaction response
function handleAddToCart(product) {
  addToCartAPI(product);
  klaviyo.track('Added to Cart', { product }); // 200ms
  fbq('track', 'AddToCart', { product }); // 150ms
  dataLayer.push({ event: 'add_to_cart', product }); // 180ms
}

// After — defer tracking to after visual update
async function handleAddToCart(product) {
  // Update cart UI immediately
  addToCartAPI(product);
  updateCartIcon(); // visual response happens fast

  // Schedule tracking for after the visual update
  await scheduler.yield();

  // Tracking runs after the browser has painted the cart update
  klaviyo.track('Added to Cart', { product });
  fbq('track', 'AddToCart', { product });
  dataLayer.push({ event: 'add_to_cart', product });
}

The visual response (cart icon updating) now happens immediately. Tracking fires after the browser has painted — the user sees the instant response, while tracking still fires correctly.

Example 3: React dropdown with 350ms INP

Scenario: A Next.js application. Clicking a navigation dropdown takes 350ms to open.

Recording: Click record → click dropdown → stop.

What you see in the flame chart:

  • Taskbar 350ms wide
  • Dominated by React internals: performSyncWorkOnRootreconcileChildren → hundreds of nested component renders
  • The dropdown opens a menu, which triggers a state update, which re-renders the entire page component tree

Diagnosis: The dropdown state is stored in a top-level component. Every click triggers a full re-render of the entire component tree — including 200+ product cards, the header, sidebar, and footer.

Fix:

jsx
// Before — dropdown state in top-level component, causes full tree re-render
function PageLayout({ products }) {
  const [dropdownOpen, setDropdownOpen] = useState(false);

  return (
    <div>
      <Nav
        dropdownOpen={dropdownOpen}
        onToggle={() => setDropdownOpen(!dropdownOpen)}
      />
      <ProductGrid products={products} /> {/* re-renders on every dropdown toggle */}
      <Sidebar />
      <Footer />
    </div>
  );
}

// After — dropdown state isolated in Nav component
function PageLayout({ products }) {
  return (
    <div>
      <Nav /> {/* manages its own dropdown state internally */}
      <ProductGrid products={products} /> {/* never re-renders for dropdown */}
      <Sidebar />
      <Footer />
    </div>
  );
}

function Nav() {
  const [dropdownOpen, setDropdownOpen] = useState(false);
  // State changes only re-render Nav and its children — not the whole page
  return (
    <nav>
      <button onClick={() => setDropdownOpen(!dropdownOpen)}>Menu</button>
      {dropdownOpen && <DropdownMenu />}
    </nav>
  );
}

Moving the dropdown state into the Nav component means the state change only re-renders Nav and its children — not the entire page. INP drops from 350ms to under 30ms.

Using the Chrome DevTools Long Tasks API

For monitoring long tasks in production — not just in DevTools — use the Long Tasks API:

javascript
// Observe long tasks in production
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.duration > 50) {
      console.warn('Long task detected:', {
        duration: Math.round(entry.duration),
        startTime: Math.round(entry.startTime),
        attribution: entry.attribution
      });

      // Send to your analytics platform
      sendToAnalytics({
        metric: 'long_task',
        duration: entry.duration,
        page: window.location.pathname
      });
    }
  }
});

observer.observe({ type: 'longtask', buffered: true });

This runs in real users' browsers and sends long task data to your analytics platform. You can identify which pages and which interactions are causing long tasks for real users — not just in your local DevTools session.

Combined with the web-vitals library for INP measurement:

javascript
import { onINP } from 'web-vitals';

onINP((metric) => {
  sendToAnalytics({
    metric: 'INP',
    value: metric.value,
    rating: metric.rating, // 'good', 'needs-improvement', 'poor'
    page: window.location.pathname,
    interaction: metric.attribution?.interactionTarget
  });
});

The interactionTarget The INP attribution tells you exactly which DOM element triggered the slow interaction — the specific button, link, or form field that caused the INP failure for real users.

Platform-specific DevTools tips

WordPress sites

WordPress sites often load dozens of scripts from different sources. In the Performance panel, look for long tasks from scripts on external domains — these are third-party scripts from plugins.

In the flame chart, hover over the script bars and look at the domain name in the tooltip. Scripts from:

  • googletagmanager.com — Google Tag Manager
  • connect.facebook.net — Facebook Pixel
  • static.hotjar.com — Hotjar
  • widget.intercom.io — Intercom chat
  • cdn.amplitude.com — Amplitude analytics

Are all common sources of long tasks on WordPress sites? Each can be deferred or delayed, as covered in how to reduce JavaScript execution time.

Use the Query Monitor WordPress plugin alongside DevTools. Query Monitor shows which plugins are adding scripts to each page — giving you the plugin name that corresponds to each external script domain.

Shopify stores

Shopify's theme JavaScript and app scripts are the primary long task sources. In the flame chart, look for:

  • Bars from cdn.shopify.com — Shopify theme JavaScript
  • Bars from app-specific CDN domains — installed app scripts

For Shopify, the DevTools approach is diagnostic. The fix is almost always removing or delaying app scripts — not modifying Shopify's core theme JavaScript directly. As covered in fix CLS from dynamic ads and embeds, many Shopify app scripts cause both CLS and INP problems simultaneously.

Next.js and React apps

React DevTools Profiler works alongside the Chrome DevTools Performance panel:

  1. Install the React DevTools browser extension
  2. Open the Profiler tab in React DevTools
  3. Click Record, interact with your page, stop recording
  4. The Profiler shows every React component render with its duration, ranked by time

Use React DevTools Profiler to identify which components are re-rendering unnecessarily. Use Chrome DevTools Performance panel to see the total main thread impact. The two tools together give you a complete picture of React-specific long task causes.

Long task fixes — decision tree

Use this decision tree after identifying a long task in DevTools:

Long task found (>50ms)
│
├── Originates from third-party script domain?
│   ├── YES → Defer with async/defer attribute
│   │         Load after user interaction
│   │         Move to Partytown web worker
│   └── NO → Continue below
│
├── Originates from React internals (performSyncWorkOnRoot)?
│   ├── YES → Add React.memo to child components
│   │         Add useCallback to event handlers
│   │         Add useMemo to expensive calculations
│   │         Move state lower in component tree
│   │         Use useTransition for non-urgent updates
│   └── NO → Continue below
│
├── Large purple style recalculation block after JS?
│   ├── YES → Reduce DOM size
│   │         Batch DOM reads and writes
│   │         Avoid layout thrashing
│   │         Use CSS transform instead of layout properties
│   └── NO → Continue below
│
└── Your own synchronous data processing?
    └── YES → Add scheduler.yield() every 50 iterations
              Move to Web Worker if truly CPU-intensive
              Cache results with useMemo or manual memoisation

How long does task analysis connect to your full performance strategy

Finding and fixing long tasks in DevTools is the diagnostic bridge between knowing you have an INP problem and knowing exactly how to fix it.

Once you have identified your long tasks:

The complete Core Web Vitals guide ties all of these fixes together into a single prioritised action plan.

Frequently asked questions

Q1. What is a long task in Chrome DevTools?

A long task is any JavaScript operation on the main thread that takes more than 50ms to complete. Chrome DevTools marks them with a red triangle in the top-right corner of the task bar in the Performance panel flame chart. Long tasks block the browser from responding to user interactions — directly causing INP failures.

Q2. How do I find long tasks in Chrome DevTools? 

Open Chrome DevTools → Performance panel → set CPU throttling to 4x → record either a page load or a specific interaction → look for bars with red triangles in the Main thread section. Click any red-triangle bar to see its duration and the specific functions causing it.

Q3. Why do I need CPU throttling when testing?

Your development laptop has a CPU 5–10x faster than a mid-range Android phone. Without throttling, tasks that take 200ms for real mobile users may take only 30ms on your machine — below the 50ms long task threshold and invisible in your recording. 4x CPU throttling simulates realistic mobile device performance.

Q4. Can long tasks affect LCP as well as INP? 

Yes. Long tasks during the page load phase prevent the browser from rendering content, directly delaying when the LCP element can paint. Long tasks in the critical load path are both an LCP problem and a potential INP problem. The Performance panel shows both LCP markers and INP markers in the Web Vitals section when both are enabled.

Q5. My flame chart shows React internals taking most of the time. What does that mean? 

It means React's rendering and reconciliation process is the primary source of your long tasks. The fix is not to replace React but to prevent unnecessary re-renders using React.memo, useCallback, useMemo, and useTransition. Move the state as low as possible in the component tree to limit how much of the tree re-renders on each state change.

Q6. How do I identify long tasks from specific plugins in WordPress? 

In the flame chart, hover over script bars and look at the domain in the tooltip. Each third-party domain corresponds to a specific plugin or service. Cross-reference the domain with your plugin list to identify which plugin is responsible. The Query Monitor plugin adds additional context by showing which plugins are registering which scripts on each page.

Q7. Does fixing long tasks always improve INP?

Fixing long tasks that occur during user interactions always improves INP. Long tasks that occur only during the initial page load (before any interactions) may improve LCP and reduce input delay but may not directly move your INP score if the interactions themselves are fast. Focus on long tasks that occur at the same time as the interactions you want to optimise.

Summary

Long tasks are the direct cause of most INP failures. Finding them requires Chrome DevTools Performance panel with CPU throttling enabled. Reading them requires understanding that red triangles mark tasks over 50ms, the flame chart shows the call stack, and the deepest bar shows the specific function doing the work.

The five-step process:

  1. Set up — open Performance panel, enable 4x CPU throttling, enable Web Vitals
  2. Record — record one specific interaction at a time, not the whole page
  3. Find — look for red triangle bars in the Main thread section
  4. Diagnose — zoom in, click through to source, identify the pattern (third-party, React re-render, synchronous processing, DOM manipulation)
  5. Fix — apply the right fix for the pattern (defer, memo, yield, or batch)

Once you know which code is causing your long tasks, the fixes are well-defined. The diagnostic step — finding the exact culprit in the flame chart — is what most developers skip. This guide gives you everything you need to stop skipping it.

Author Image

Hardeep Singh

Hardeep Singh is a tech and money-blogging enthusiast, sharing guides on earning apps, affiliate programs, online business tips, AI tools, SEO, and blogging tutorials. About Author.

Previous Post