You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/sign-in is Studio's main-thread hotspot, and almost all of the blocking is third-party
marketing tags that src/App.tsx loads eagerly above the router. This is a standing
condition, not a spike — which is why the usual adjacent-window comparison never surfaced
it. p95 and p99 are flat across 14d and 30d.
The measurement
@long_task.blocking_duration p95 (LoAF blocking time — the actual main-thread cost, not
frame duration), production RUM app f590deee, 30d to 2026-09-07:
Scope
frames
p95 blocking
@view.url_hash:*sign-in*
5,572
1,136ms
everything else
22,964
134ms
An 8.5× gap. Stable over time — sign-in p95 was 1,182ms on 14d, 1,136ms on 30d.
Sign-in is one screen out of ~40, and it accounts for 19.5% of all long animation frames
in the application (5,572 of 28,536).
Reach, 30d:
335 sessions emitted at least one long animation frame on sign-in, out of 1,322 sessions
that viewed sign-in at all (25%).
314 frames blocked the main thread for over 1 second, across 84 sessions (6.4% of
sign-in sessions).
Worst single frame: 5,445ms duration / 5,392ms blocking.
That last ratio matters. blocking_duration ≈ duration on the worst frames, so this is real
main-thread work — not the rAF-starvation pattern (render_start - start_time ≈ duration
with an empty scripts array) that made a previous long-task investigation a false positive. @long_task.entry_type is long-animation-frame for 28,303 of 28,536 frames over the same
30d, so the collection mode has not changed either.
Attribution
Taking only frames where LoAF attributed exactly one distinct script host — so the
attribution is unambiguous — over 14d of sign-in frames:
Attributed host
frames
total blocking
avg/frame
static.reo.dev (Reo.dev intent pixel)
90
26,619ms
296ms
www.googletagmanager.com
41
12,295ms
300ms
fabric.harper.fast (our own bundle)
44
9,702ms
220ms
connect.facebook.net
21
4,949ms
236ms
js.stripe.com
11
2,796ms
254ms
www.redditstatic.com
6
430ms
72ms
capi-automation.s3.us-east-2.amazonaws.com
4
328ms
82ms
snap.licdn.com (LinkedIn Insight)
3
173ms
58ms
js-na2.hs-analytics.net (HubSpot)
9
115ms
13ms
Third-party tags are ~48s of the ~58s of unambiguously-attributed blocking. Our own bundle is
9.7s of it — worth its own look, but it is not the bulk.
The most common individual invokers are TimerHandler:setTimeout | static.reo.dev (118), static.reo.dev bare (43), SCRIPT[src="static.reo.dev…"] (29), IdleRequestCallback | static.reo.dev (26), Permissions.query.then | static.reo.dev (17),
and TimerHandler:setTimeout | www.googletagmanager.com (39).
Mechanism
src/App.tsx calls all three integrations unconditionally, above
the router, on first render:
useReo (src/integrations/reo/reo.ts) injects static.reo.dev from a useEffect with no
deferral.
useGTM (src/integrations/google/gtm.ts) injects container GTM-5QQX432, which in turn
loads Facebook, LinkedIn, HubSpot (analytics + collected-forms + banner), Reddit, Apollo,
and aplo-evnt.com. None of those hosts appear anywhere in this repo — they arrive through
the container, so the blast radius of the GTM tag is whatever marketing has configured.
Because these are above the router, they load on every entry point. Sign-in absorbs the
whole cost because sign-in is where an unauthenticated visitor's initial load happens — all
seven-plus tag bundles boot concurrently with app hydration. Once past the auth wall, route
changes are cheap because the scripts are already parsed, which is exactly the 134ms figure
in the table above.
Note also #1620: ~90% of Reo's own event POSTs have been rejected 400 for 30+ days. So the
single largest blocking contributor on the sign-in critical path is currently paying full
main-thread cost for telemetry that mostly does not land.
Honest caveats
INP is not degraded.@view.interaction_to_next_paint p75 is 48ms on sign-in vs 40ms
elsewhere (n=378 / n=4,189, 30d). This is a load-phase responsiveness cost, not an
interaction-latency one, and it will not show up in an INP dashboard.
These are p95/p99 tails on a low-traffic app (2,546 sessions in 30d). The tail is where a
slow device or a slow network lands, which is also where a sign-in abandonment would come
from — but nobody has tied a specific abandonment to it.
Suggested direction
Ordered cheapest-first; none of these removes a tag:
Get the tags off the initial-load critical path. Defer useReo() and useGTM() behind requestIdleCallback (or a setTimeout after first paint) instead of firing them in a
mount effect. Preserves every tag and every pageview; only the timing moves.
Separately, look at the 9.7s attributed to our own bundle on sign-in — smaller, but it is
ours to fix outright.
(1) is a measurement-vs-performance tradeoff that marketing owns, not purely an engineering
call — deferring a tag can shift attribution for the acquisition funnel — so this is filed for
that conversation rather than fixed unilaterally.
Reproducing the numbers
APP='@application.id:f590deee-4bac-49b4-a202-3b6963d9721d'
pup rum aggregate --query "$APP @type:long_task @view.url_hash:*sign-in*" \
--compute 'percentile(@long_task.blocking_duration, 95)' --from 30d --to now
pup rum aggregate --query "$APP @type:long_task -@view.url_hash:*sign-in*" \
--compute 'percentile(@long_task.blocking_duration, 95)' --from 30d --to now
pup rum events --query "$APP @type:long_task @view.url_hash:*sign-in*" \
--from 14d --to now --limit 600 # then group scripts[].source_url by host
Values come back in nanoseconds. Found by the daily RUM review, 2026-09-07.
/sign-inis Studio's main-thread hotspot, and almost all of the blocking is third-partymarketing tags that
src/App.tsxloads eagerly above the router. This is a standingcondition, not a spike — which is why the usual adjacent-window comparison never surfaced
it. p95 and p99 are flat across 14d and 30d.
The measurement
@long_task.blocking_durationp95 (LoAF blocking time — the actual main-thread cost, notframe
duration), production RUM appf590deee, 30d to 2026-09-07:@view.url_hash:*sign-in*An 8.5× gap. Stable over time — sign-in p95 was 1,182ms on 14d, 1,136ms on 30d.
Sign-in is one screen out of ~40, and it accounts for 19.5% of all long animation frames
in the application (5,572 of 28,536).
Reach, 30d:
that viewed sign-in at all (25%).
sign-in sessions).
That last ratio matters.
blocking_duration ≈ durationon the worst frames, so this is realmain-thread work — not the rAF-starvation pattern (
render_start - start_time ≈ durationwith an empty
scriptsarray) that made a previous long-task investigation a false positive.@long_task.entry_typeislong-animation-framefor 28,303 of 28,536 frames over the same30d, so the collection mode has not changed either.
Attribution
Taking only frames where LoAF attributed exactly one distinct script host — so the
attribution is unambiguous — over 14d of sign-in frames:
static.reo.dev(Reo.dev intent pixel)www.googletagmanager.comfabric.harper.fast(our own bundle)connect.facebook.netjs.stripe.comwww.redditstatic.comcapi-automation.s3.us-east-2.amazonaws.comsnap.licdn.com(LinkedIn Insight)js-na2.hs-analytics.net(HubSpot)Third-party tags are ~48s of the ~58s of unambiguously-attributed blocking. Our own bundle is
9.7s of it — worth its own look, but it is not the bulk.
The most common individual invokers are
TimerHandler:setTimeout | static.reo.dev(118),static.reo.devbare (43),SCRIPT[src="static.reo.dev…"](29),IdleRequestCallback | static.reo.dev(26),Permissions.query.then | static.reo.dev(17),and
TimerHandler:setTimeout | www.googletagmanager.com(39).Mechanism
src/App.tsxcalls all three integrations unconditionally, abovethe router, on first render:
useReo(src/integrations/reo/reo.ts) injectsstatic.reo.devfrom auseEffectwith nodeferral.
useGTM(src/integrations/google/gtm.ts) injects containerGTM-5QQX432, which in turnloads Facebook, LinkedIn, HubSpot (analytics + collected-forms + banner), Reddit, Apollo,
and
aplo-evnt.com. None of those hosts appear anywhere in this repo — they arrive throughthe container, so the blast radius of the GTM tag is whatever marketing has configured.
Because these are above the router, they load on every entry point. Sign-in absorbs the
whole cost because sign-in is where an unauthenticated visitor's initial load happens — all
seven-plus tag bundles boot concurrently with app hydration. Once past the auth wall, route
changes are cheap because the scripts are already parsed, which is exactly the 134ms figure
in the table above.
Note also #1620: ~90% of Reo's own event POSTs have been rejected
400for 30+ days. So thesingle largest blocking contributor on the sign-in critical path is currently paying full
main-thread cost for telemetry that mostly does not land.
Honest caveats
@view.interaction_to_next_paintp75 is 48ms on sign-in vs 40mselsewhere (n=378 / n=4,189, 30d). This is a load-phase responsiveness cost, not an
interaction-latency one, and it will not show up in an INP dashboard.
is dead ([RUM] Core Web Vitals collection is dead — LCP/FCP dropped 55% → 0% of initial loads around 2026-07-04, blinding #1405 #1570) — LCP/FCP are absent from initial loads, so the obvious "does this delay
first paint on the sign-in funnel" query has no data behind it. Fixing [RUM] Core Web Vitals collection is dead — LCP/FCP dropped 55% → 0% of initial loads around 2026-07-04, blinding #1405 #1570 would let us
quantify the win rather than infer it.
slow device or a slow network lands, which is also where a sign-in abandonment would come
from — but nobody has tied a specific abandonment to it.
Suggested direction
Ordered cheapest-first; none of these removes a tag:
useReo()anduseGTM()behindrequestIdleCallback(or asetTimeoutafter first paint) instead of firing them in amount effect. Preserves every tag and every pageview; only the timing moves.
contributor and its payloads are being rejected.
ours to fix outright.
(1) is a measurement-vs-performance tradeoff that marketing owns, not purely an engineering
call — deferring a tag can shift attribution for the acquisition funnel — so this is filed for
that conversation rather than fixed unilaterally.
Reproducing the numbers
Values come back in nanoseconds. Found by the daily RUM review, 2026-09-07.