Description
Frontegg's React SDK has two CPU-intensive polling loops that run continuously while the application is idle, causing significant CPU consumption even when the user is fully authenticated and not interacting with the page.
Issue 1: requestAnimationFrame polling loop in HideChildrenIfFronteggRoutes
The HideChildrenIfFronteggRoutes component runs a self-scheduling requestAnimationFrame loop that checks window.location.pathname every frame (~60fps) to detect route changes to Frontegg-hosted routes (e.g. /account/login).
Source: @frontegg/react bundle (observed at offset ~28271)
Trace evidence: In a Chrome performance trace over ~11 seconds of idle time, we recorded 1,191 RequestAnimationFrame events originating from this callback, making it the single largest CPU consumer in the application.
Why this is unnecessary: The component already has popstate and custom event listeners that handle URL changes. The rAF loop appears to be a fallback for pushState/replaceState calls (which don't fire popstate), but a more efficient approach would be to patch pushState/replaceState to dispatch events, rather than polling at 60fps indefinitely.
Issue 2: setInterval at 50ms in login-box bundle
The Frontegg login-box bundle installs a setInterval with a ~50ms interval that continues running even after the user is fully authenticated. Over an 11-second idle trace, this timer fired 208 times, consuming 1,136ms of scripting CPU.
Source: frontegg/login-box bundle
Impact
| Metric |
Before fix |
After fix |
| Chrome idle CPU |
~20% |
<1% |
| Brave idle CPU |
~100% |
<1% |
| Scripting time (11s idle trace) |
601ms |
13ms |
This affects all customers using the @frontegg/react SDK. Users on lower-powered devices or battery-constrained laptops are particularly impacted.
Steps to Reproduce
- Set up a React app with
@frontegg/react using hostedLoginBox={false}
- Log in as any user
- Open Chrome DevTools → Performance tab → Record for 10–15 seconds while idle
- Observe continuous
RequestAnimationFrame and TimerFire events originating from Frontegg bundles
Expected Behavior
When the user is authenticated and the application is idle, Frontegg should not consume any meaningful CPU. Route detection should use event-driven mechanisms rather than polling.
Our Workaround
We currently intercept requestAnimationFrame and suppress callbacks that self-reschedule 60+ times consecutively (threshold-based detection of infinite loops), and detect/clear short-interval timers after confirming they're polling loops. We also patch pushState/replaceState to dispatch popstate events so Frontegg's existing listener still detects route changes.
This works but is fragile and shouldn't be necessary.
Environment
@frontegg/react: 7.12.18
- React 19
- Chromium-based browsers (Chrome, Brave, Edge)
Description
Frontegg's React SDK has two CPU-intensive polling loops that run continuously while the application is idle, causing significant CPU consumption even when the user is fully authenticated and not interacting with the page.
Issue 1:
requestAnimationFramepolling loop inHideChildrenIfFronteggRoutesThe
HideChildrenIfFronteggRoutescomponent runs a self-schedulingrequestAnimationFrameloop that checkswindow.location.pathnameevery frame (~60fps) to detect route changes to Frontegg-hosted routes (e.g./account/login).Source:
@frontegg/reactbundle (observed at offset ~28271)Trace evidence: In a Chrome performance trace over ~11 seconds of idle time, we recorded 1,191
RequestAnimationFrameevents originating from this callback, making it the single largest CPU consumer in the application.Why this is unnecessary: The component already has
popstateand custom event listeners that handle URL changes. The rAF loop appears to be a fallback forpushState/replaceStatecalls (which don't firepopstate), but a more efficient approach would be to patchpushState/replaceStateto dispatch events, rather than polling at 60fps indefinitely.Issue 2:
setIntervalat 50ms in login-box bundleThe Frontegg login-box bundle installs a
setIntervalwith a ~50ms interval that continues running even after the user is fully authenticated. Over an 11-second idle trace, this timer fired 208 times, consuming 1,136ms of scripting CPU.Source:
frontegg/login-boxbundleImpact
This affects all customers using the
@frontegg/reactSDK. Users on lower-powered devices or battery-constrained laptops are particularly impacted.Steps to Reproduce
@frontegg/reactusinghostedLoginBox={false}RequestAnimationFrameandTimerFireevents originating from Frontegg bundlesExpected Behavior
When the user is authenticated and the application is idle, Frontegg should not consume any meaningful CPU. Route detection should use event-driven mechanisms rather than polling.
Our Workaround
We currently intercept
requestAnimationFrameand suppress callbacks that self-reschedule 60+ times consecutively (threshold-based detection of infinite loops), and detect/clear short-interval timers after confirming they're polling loops. We also patchpushState/replaceStateto dispatchpopstateevents so Frontegg's existing listener still detects route changes.This works but is fragile and shouldn't be necessary.
Environment
@frontegg/react: 7.12.18