INP under 100 milliseconds on a Framer Motion heavy page
How RankSmith keeps Interaction to Next Paint under 100 milliseconds on pages that lean heavily on Framer Motion, without turning off the interactions.
The RankSmith home page runs Framer Motion on the hero, on every section (via Reveal), on a marquee, and on animated counters. It still targets INP under 100 ms. Here is how.
What is INP and what is the current 2026 threshold?
INP is the Core Web Vital that replaced First Input Delay in March 2024. Unlike FID, which only measured the first interaction, INP measures every interaction on the page and reports the 98th percentile. That single change raised the bar significantly. A page that had a snappy first click but janky scroll linked animations would pass FID and fail INP.
Google's current thresholds, unchanged since 2024:
- Good, 0 to 200 ms.
- Needs improvement, 200 to 500 ms.
- Poor, 500 ms and above.
Our internal target at RankSmith is 100 ms on home and primary content pages, and 150 ms on secondary pages. We buy the headroom because Core Web Vitals measurements report a rolling 28 day 75th percentile. If the target is 200 and we ship at 195, one slow week moves the number over the line and rankings drop before we notice. Shipping at 100 gives us a full 100 ms of buffer for real user conditions.
Which Framer Motion patterns blow your INP budget?
Framer Motion itself is not the problem. Out of the box it animates transform and opacity through the Web Animations API, which runs on the compositor off the main thread. Your React tree is not re-rendered, the main thread stays free, and INP is close to perfect.
The problem is how Framer Motion gets used. Three patterns we delete whenever we see them on client audits.
First, layoutId and <LayoutGroup> on a large subtree. The layout animation runs on the compositor but the measurement phase requires a React render plus a DOM layout on every child at animation start. Fifty children is usually fine. Two hundred children on a mid range Android stalls the main thread for over 150 ms.
Second, useScroll or useTransform driving a prop that feeds into a React render. Each scroll tick triggers a re-render. If the re-render touches a large tree, every scroll tick pays the cost. INP is measured on the tap that starts the scroll, and the tap lands on a frozen main thread.
Third, an event handler that animates a property that triggers layout. Width, height, top, left, margin, padding. These properties cannot run on the compositor and the browser has to redo layout. Framer Motion does not prevent this, you have to keep yourself honest.
Fourth, and less visible, AnimatePresence on a ref heavy component. Exit animations require the component to remain in the tree for the duration, and if React has already scheduled new work behind it, the paint queues up.
How RankSmith keeps the home page under 100 ms with Reveal, Marquee, and CountUp.
Four specific design decisions keep our home page quick even with the motion system we ship.
Reveal uses whileInView with once: true. After the element has animated in once, the intersection observer unmounts. Scrolling past the animated section carries zero main thread cost the second time. The y transform is 16 pixels, the duration 0.55 seconds, the ease [0.22, 1, 0.36, 1]. Everything the compositor can handle directly. Here is the primitive as shipped on the site:
export function Reveal({ children, delay = 0, y = 16 }: RevealProps) {
const reduce = useReducedMotion();
return (
<motion.div
initial={{ opacity: 0, y: reduce ? 0 : y }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-10% 0px -10% 0px" }}
transition={{ duration: reduce ? 0 : 0.55, ease: [0.22, 1, 0.36, 1], delay }}
>
{children}
</motion.div>
);
}
Marquee is a CSS animation. No JavaScript scroll listener, no React work. A @keyframes declaration translates the inner track and the browser handles the rest. The only job React has is rendering the initial markup. Our home page marquee runs at 60 fps on a four year old Android. The main thread stays idle.
CountUp writes directly to a DOM ref via requestAnimationFrame. When the viewport trigger fires, we start an RAF loop that updates element.textContent every frame until the number reaches the target. React is not involved after mount. A React driven counter on the same home page would re-render the entire component every frame. Our version costs roughly 0.3 ms per frame.
The hero animations run on SVG path length and opacity only. No layout animations, no layoutId, no LayoutGroup. Framer Motion animates pathLength via SMIL equivalents which the compositor handles.
One rule that works across all four. If an animation needs to write to React state on every frame, we look again. Most of the time the answer is to write to a ref instead, or to move the value into a CSS custom property that the browser animates directly.
What do we measure, and with what?
We use three tools in order of trust.
CrUX (Chrome User Experience Report) is the ground truth. It reports the 75th percentile INP across real Chrome users for the last 28 days. It lags by a month, which is a feature not a bug: it means panic reactions to a one day spike are impossible. We pull CrUX data via the PageSpeed Insights API or the CrUX BigQuery dataset for monthly reviews.
Vercel Speed Insights runs on every RankSmith site. It reports per route INP, LCP, CLS, and TTFB live, segmented by device and country. We watch it daily in the week after a change, weekly otherwise.
Chrome DevTools Performance panel is how we reproduce a regression. Record the interaction on a 4x CPU throttle and a "Fast 3G" network (simulating a mid range Android on a slow mobile connection). The waterfall shows exactly which task blocked the main thread. Paired with the Web Vitals extension, the panel highlights the specific interaction measurement.
We never trust the PageSpeed Insights lab INP number in isolation. It is a synthetic measurement on a fixed trace, not a distribution across real users. Use it as a smoke test, not an audit.
When do we delete an animation instead of optimising it?
Not every animation earns its main thread cost. The RankSmith editorial test is three questions.
Does the animation carry information? A Reveal on a new section arriving tells the reader "this is a separate idea". A CountUp on a real metric tells the reader "this number is important". A fade on a random paragraph does not carry information. It is noise.
Does the animation change comprehension if removed? If we delete it and the user still understands the page the same way, it is not earning its cost.
Does the animation cost under five milliseconds on a mid range Android? Measured in the Performance panel with 4x CPU throttle. If the answer is no, either the animation gets rewritten to use transform and opacity only, or it gets cut.
Three real deletions from the RankSmith home page during the last performance review:
- A staggered fade on the hero metric row, 14 ms of main thread work, no comprehension change. Deleted.
- A layout animation on the services bento hover, 32 ms of work, replaced with a CSS transform transition, 1 ms.
- A
useScrolldriven parallax on a background image, 8 ms per scroll tick, deleted entirely.
Every decision here has to pass both the design and performance teams. We do not delete an animation just because it is expensive, and we do not keep it just because it is pretty. The gate is whether the interaction stays under 100 ms on the slowest device our target audience uses.
If you want us to audit INP on a Framer Motion heavy Next.js site, start with the free audit. We return a list of animations ranked by cost, a trace of the worst offenders, and a rewrite plan that keeps the ones that earn their place. Our SXO service covers the full Core Web Vitals discipline if you want the full sweep.
Frequently asked questions
What counts as a good INP in 2026?
Does Framer Motion cause bad INP by default?
How do you measure INP in production?
When do you delete an animation instead of optimising it?
More field notes
All field notesReady when you are
Want this level of work on your site?
Book a thirty minute strategy call. We will audit your current rankings in Google and in AI engines, and map the fastest wins we can ship in the next sixty days.