Extended: where its trading screen loses time, and what to fix

Measured from the Netherlands in a logged-in Chrome, October 2026.

In short. On a warm reload the screen is trade-ready after 5.1 s (median of 5 loads), 21 of 27 perpetual trading screens, possible rank 13 to 24; after an uncached reload 5.4 s. The largest bottleneck: The HTML takes 0.7 s; it is marked no-store and missed the edge cache. First change to try: Let CloudFront cache the HTML shell (short max-age with stale-while-revalidate) instead of no-store, and fetch the page address and version.json once, off the start-up path.

Three measurements appear on this page, and their times differ. Rank and results come from the campaign's timed reloads. The diagnostic capture and the recorded reload are single loads made with recording switched on, which slows the page: read them for the order of events and the gaps, not for totals.

Resultscampaign: 5 warm and 5 uncached reloads

Warm reloadmedian 5.1 s, range 4.6 s–6.1 s; loads: 5.3 s, 5.1 s, 4.7 s, 4.6 s, 6.1 s
Uncached reloadmedian 5.4 s, range 5.1 s–5.8 s; loads: 5.4 s, 5.8 s, 5.4 s, 5.4 s, 5.1 s
Standing21 of 27 by median; possible rank 13 to 24. 2.6 s behind the fastest, Thalex (2.4 s): 2.1 times as long. The possible rank is the range the measurements leave open: it counts only the exchanges that clearly beat this one and those it clearly beats. Exchanges whose ranges overlap cannot be told apart.
Loads ready5 of 5 warm, 5 of 5 uncached
Notesrecent trades not measured: inactive tab

Where the time goescampaign medians, warm reload

Panels in the order they first showed real, usable data on a warm reload. The coloured part of each row is the time that panel added after the one before it. The last row is trade-ready: every panel is ready and the page has stopped moving.

0 s1 s2 s3 s4 s5 s
Price2.9 s
Order form4.2 s +1.3 s
Chart4.3 s +0.1 s
Order book4.3 s +0.0 s
Account panel4.6 s +0.3 s
Trade-ready5.1 s +0.4 s settling

Stack

React, built with Vite; TradingView chart library from cdn.extended.exchange; two wallet SDKs (Dynamic and Privy) plus WalletConnect/Reown, viem and starknet-crypto; a service worker.

Delivery

HTML from AWS S3 through CloudFront, marked no-store; in the capture it missed the edge cache (x-cache: Miss). 225 of the app's static files carry no cache-control header. On a warm reload a service worker answers 236 of the 414 requests made before trade-ready.

HostRoleCDN edge seenConnectResponse
app.extended.exchangepageCloudFront Amsterdam13 ms10 ms
api.starknet.extended.exchangemarket data—242 ms233 ms

Median of up to 10 attempts from the test machine. Response time includes the server's own time, so it is not a distance.

What happened, in orderdiagnostic capture 1 October, uncached

From one uncached diagnostic load recorded on 1 October 2026 (cache disabled, browser extensions active), so totals are slower than the campaign's timed loads; file names, sizes, headers, order of events and main-thread times are what the findings rely on. A main-thread time given for a script counts all the work that starts in that script, including code it calls in other files, so it shows where start-up work begins, not what one library costs. Endpoint paths were masked when the capture was saved.

WhenWhat
0.73 sHTML arrives: a CloudFront miss to S3 (no-store). The 3 October recorded load measured 0.70 s.
0.91–1.47 sStartup scripts download in parallel: dynamic-labs (0.9 MB compressed, 3.4 MB unpacked), viem (2.3 MB), privy (2.3 MB), starknet-crypto (1.4 MB), components (1.1 MB), reown (0.5 MB), walletconnect (0.45 MB): about 12 MB unpacked, most of it wallet and chain code.
1.87 sFirst paint. Over the whole load, 1.29 s of main-thread work starts in index.js.
2.12 sThe live feed opens (app.extended.exchange); handshake done at 2.62 s; its first message arrives only at 5.95 s.
2.50 sA 2.1 MB file from iconic.dynamic-static-assets.com (Dynamic's icons); the same 2.1 MB file is fetched again at 5.65 s.
2.96 sThe Privy iframe loads its script chunks.
4.15 sA 1.0 MB JSON response sent without compression (no-store); the same 1.0 MB response is requested again at 5.60 s.
5.67 sThe page header shows the market; price at 6.31 s; order book at 7.42 s.
7.76 sChart drawn: trade-ready in this load. 23 long tasks took 3.4 s of main thread.

Recorded warm reload, 3 October

One warm reload recorded with Chrome's performance trace. Recording slows the page, so read the order and the gaps, not the total.

WhenWhat
0.7 sHTML arrives
1.2 sFirst market-data request
2.7 sFirst frame sent on a live feed
2.8 sPrice ready
2.8 saccount-info ready
3.0 sFirst frame received on a live feed
4.2 sOrder form ready
4.3 sChart ready
4.3 sOrder book ready
4.7 spositions ready
5.7 sTrade-ready

410 requests before trade-ready; 10 long main-thread tasks (over 50 ms) before trade-ready, longest 189 ms; 251 script requests before the first panel; 0 requests over HTTP/1.1.

Request waterfalldiagnostic capture 1 October, uncached

70 of the 308 requests (the page itself, the longest and the largest) started before market data was ready in the 1 October uncached capture, in start order. The outlined part of a bar is waiting for the server; the solid part is downloading. Rows are numbered so a request can be pointed to. The numbers on the right are the size received and the total time. Vertical lines mark when a panel had data in this capture.

PageScriptFont, media, other fileData requestImagewaiting for the serverdownloading

0 s0 s1 s1 s2 s2 s3 s3 s4 s4 s5 s5 s6 s6 s7 s7 s1app.extended.exchange17 kB38 ms2app.extended.exchange/vie…503 kB502 ms3app.extended.exchange/sta…413 kB508 ms4app.extended.exchange/dyn…947 kB558 ms5app.extended.exchange/pri…717 kB553 ms6app.extended.exchange/com…333 kB526 ms7app.extended.exchange/emb…1 kB537 ms8app.extended.exchange/wal…1 kB536 ms9app.extended.exchange/en-…40 kB539 ms10app.extended.exchange/use…1 kB537 ms11app.extended.exchange/mas…1 kB535 ms12app.extended.exchange/ref…915 B537 ms13app.extended.exchange/use…1 kB536 ms14app.extended.exchange/use…1 kB536 ms15app.extended.exchange/reg…1 kB922 ms16app.extended.exchange2 kB798 ms17iconic.dynamic-static-ass…976 kB128 ms18explorer-api.walletconnec…173 kB131 ms19app.extended.exchange1220 ms20app.extended.exchange1165 ms21privy.app.extended.exchan…2 kB35 ms22privy.app.extended.exchan…7 kB662 ms23privy.app.extended.exchan…61 kB667 ms24privy.app.extended.exchan…41 kB678 ms25privy.app.extended.exchan…4 kB677 ms26privy.app.extended.exchan…2 kB700 ms27privy.app.extended.exchan…91 kB701 ms28privy.app.extended.exchan…28 kB705 ms29privy.app.extended.exchan…45 kB708 ms30privy.app.extended.exchan…3 kB707 ms31privy.app.extended.exchan…106 kB727 ms32privy.app.extended.exchan…36 kB717 ms33privy.app.extended.exchan…6 kB717 ms34privy.app.extended.exchan…15 kB711 ms35privy.app.extended.exchan…50 kB726 ms36privy.app.extended.exchan…11 kB718 ms37privy.app.extended.exchan…16 kB724 ms38privy.app.extended.exchan…12 kB724 ms39privy.app.extended.exchan…12 kB724 ms40privy.app.extended.exchan…6 kB725 ms41privy.app.extended.exchan…31 kB744 ms42privy.app.extended.exchan…25 kB740 ms43privy.app.extended.exchan…10 kB739 ms44privy.app.extended.exchan…108 kB743 ms45privy.app.extended.exchan…58 kB742 ms46privy.app.extended.exchan…32 kB743 ms47privy.app.extended.exchan…74 kB754 ms48privy.app.extended.exchan…9 kB740 ms49privy.app.extended.exchan…20 kB740 ms50privy.app.extended.exchan…12 kB741 ms51privy.app.extended.exchan…9 kB740 ms52privy.app.extended.exchan…257 B741 ms53app.extended.exchange160 kB1167 ms54app.extended.exchange992 kB138 ms55app.extended.exchange362 B725 ms56app.extended.exchange1 kB745 ms57app.extended.exchange436 B717 ms58app.extended.exchange316 B711 ms59app.extended.exchange992 kB148 ms60app.extended.exchange316 B575 ms61app.extended.exchange334 B700 ms62iconic.dynamic-static-ass…976 kB284 ms63app.extended.exchange569 B576 ms64app.extended.exchange1 kB540 ms65app.extended.exchange785 B570 ms66app.extended.exchange882 B561 ms67app.extended.exchange798 B560 ms68app.extended.exchange302 B551 ms69app.extended.exchange333 B554 ms70app.extended.exchange258 B545 msprice 6.3 sorder book 7.4 schart 7.8 s
Download this figure as an image:

Bottlenecks and fixes, largest firstdiagnostic capture 1 October, uncached

EX-1The HTML takes 0.7 s; it is marked no-store and missed the edge cache.grade B
Evidence
1 October capture: 726 ms to the first byte, served from S3 through CloudFront with no-store and x-cache Miss. 3 October recorded load: 696 ms. A timed load shows the same 0.7 s on other small requests to the same host: version.json (45 bytes) takes 0.71 s, and the page address /trade/BTC-USD is fetched two more times at 0.69 and 0.71 s each. One capture does not prove every visit misses the cache.
Gap observed
0.73 s to the HTML response
Holds back
Every panel: nothing is shown before this ends.
Fix
Let CloudFront cache the HTML shell (short max-age with stale-while-revalidate) instead of no-store, and fetch the page address and version.json once, off the start-up path.
Where
S3 object metadata or CloudFront cache policy for index.html and version.json; the code that re-fetches /trade/BTC-USD.
Verify
DevTools → Network → document Timing: waiting for server response under 100 ms; x-cache Hit; one request for the page address.
EX-2About 12 MB of startup JavaScript, mostly two wallet SDKs and chain libraries.grade B
Evidence
All requested at 0.91 s, before the first paint at 1.87 s: dynamic-labs-O19mXtmw.js 3.5 MB unpacked, viem-IUfPZCfD.js 2.4 MB, privy-Cs_vOTKE.js 2.3 MB, starknet-crypto-_hw84zza.js 1.5 MB, components-C8PHz8Zq.js 1.2 MB, reown-BzSNX7oM.js 0.5 MB and walletconnect-OZZDLUeQ.js 0.5 MB. Dynamic and Privy are two wallet SDKs on the same page. The WalletConnect wallet list (1.2 MB unpacked) follows at 2.54 s.
Measured
about 12 MB of startup JavaScript, including two wallet SDKs and chain libraries
Holds back
Start-up as a whole; which panel waits for this work is not established.
Fix
Keep one wallet SDK, and load it and the chain libraries after the trading screen is shown or on the first wallet action.
Where
Wallet provider set-up in the app shell; Vite manual chunks for dynamic-labs, privy, viem, starknet-crypto, reown and walletconnect.
Verify
DevTools → Network: dynamic-labs, privy and viem start after the first chart paint.
EX-3The 1.0 MB market list is fetched twice per load, uncompressed, and a 2.1 MB icon file twice.grade B
Evidence
All 20 older timed loads request /api/v1/info/markets twice (990 KB, 0.4 s apart) and the Dynamic icon file (icons/sprite.svg, 2.1 MB unpacked, cached for only 10 minutes) twice. In the 1 October capture the two 1.0 MB JSON responses are marked no-store and sent without compression (4.15 and 5.60 s). In the 3 October recorded warm load two responses of that size stay open from 2.5 and 2.9 s until 5.4 s, after the chart and book are ready. The name comes from different loads than the headers, matched by host, size and order.
Measured
two 1.0 MB market-list responses and two 2.1 MB icon-file fetches
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Request /api/v1/info/markets once and reuse the result; serve it with br or gzip. Load the Dynamic icon file once, or only when the wallet modal opens.
Where
The code that requests /api/v1/info/markets (it goes out twice); compression settings for /api/v1; Dynamic icon loading.
Verify
DevTools → Network, filter "info/markets": one request, with content-encoding br or gzip.
EX-4225 static files have no cache-control header.grade B
Evidence
Content-hashed app files (220 scripts, 3 fonts, 1 stylesheet, 1 image) are served without cache-control, so each browser decides for itself how long to keep them. The CDN does hold them (x-cache Hit) and the service worker serves them on a warm reload, so this costs most on a first visit and after a new release.
Measured
225 static files without a cache-control header
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Serve hashed assets with cache-control: max-age=31536000, immutable.
Where
S3 metadata or CloudFront response headers policy for /assets/.
Verify
DevTools → Network → Headers on dynamic-labs-*.js: the cache-control header is present.
EX-5The feed is connected at 2.6 s but delivers its first message at 6.0 s.grade C
Evidence
1 October capture: feed handshake at 2.62 s, first message at 5.95 s, price at 6.31 s. The price follows the first message by 0.36 s, which suggests the wait is for the message and not for drawing. 3 October recorded warm load: the first frame is sent at 2.68 s and the first one received at 3.01 s, and the price shows at 2.78 s, before that socket has delivered anything, so on a warm load the first price probably comes from another source. The captures do not keep the frames, so they do not show when the subscription is sent.
Gap observed
3.3 s between the feed handshake and its first message; the price follows 0.36 s later
Holds back
Probably the price (median 2.9 s in the timed loads): the timing points to it, but the captures do not show that this panel waits for it.
Fix
Send the market subscription as soon as the socket is open, and find why no message arrives for 3.3 s after the handshake on an uncached load.
Where
Feed client start-up; the code that sends the first subscription.
Verify
DevTools → Network → WS → Messages: the subscription is sent within 100 ms of the socket opening and the first message arrives within 0.5 s.
EX-6Trade-ready comes 0.8 s after the chart and book: the positions panel and the chart are still animating.grade C
Evidence
All 10 ranked loads have the positions panel last (warm medians: chart and book 4.3 s, positions 4.6 s, trade-ready 5.1 s; median wait inside the loads 0.78 s). During that wait the positions panel is still animating or not yet filled in all 10, the chart is still animating in all 10, and images are still loading in 5. Recorded warm load: chart and book at 4.35 s, the chart's last animation gone by 5.03 s. That load's trade-ready of 5.68 s is 0.65 s late because of a pause in our own sampling, so it is not the page's time.
Gap observed
0.78 s median between chart and book and trade-ready inside the ten ranked loads
Holds back
Trade-ready itself: the page counts as ready only when nothing in a panel is still animating or loading.
Fix
Find what the positions panel waits for after the market panels are shown, and record a reload with DevTools → Animations to see what still animates in the chart and the positions panel after their data is drawn.
Where
The positions panel and its data; the chart panel's loading states.
Verify
DevTools → Performance: the positions panel fills within 0.3 s of the order book; nothing in the chart animates after the candles appear.

Grade B: the capture shows the problem directly. Grade C: the order of events in the capture points to it; the dependency is for the team to confirm. The order is our judgement of each finding's effect on trade-ready, largest first; it is not sorted by gap. A gap is the time between two observed events or the time one piece of work takes; gaps overlap and do not add up. Where a finding is about size or count and no time was measured, the row says what was measured instead. Holds back names the panel the finding delays. Nothing here is graded higher, because no fix was confirmed by changing a page and measuring again.

How this was measured

Timings: 5 warm and 5 uncached reloads in a seeded random order across all exchanges, each judged against a checklist frozen for this page before the campaign (this page's stored loads were scored again afterwards with one change: a dash in the positions table is read as no positions, where it was first read as still loading); trade-ready is the first moment every checklist panel shows real data, nothing is still loading, and the layout holds still for 0.5 s. The findings on this page come from separate recorded loads, which are never part of the timings. Full method.