TxFlow: 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 4.3 s (median of 5 loads), 12 of 27 perpetual trading screens, possible rank 10 to 15; after an uncached reload 4.7 s. The largest bottleneck: The react-router chunk starts 2.4 s of main-thread work. First change to try: Record a start-up profile and find what runs from the react-router chunk (route modules imported at start-up are the first thing to check); split it by route. Batch the element-size reads in the function the profile labels pt.

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 4.3 s, range 4.1 s–4.5 s; loads: 4.1 s, 4.3 s, 4.4 s, 4.5 s, 4.1 s
Uncached reloadmedian 4.7 s, range 4.5 s–5.2 s; loads: 5.2 s, 4.7 s, 4.8 s, 4.5 s, 4.7 s
Standing12 of 27 by median; possible rank 10 to 15. 1.9 s behind the fastest, Thalex (2.4 s): 1.8 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 s
Price3.4 s
Chart3.4 s +0.0 s
Order book3.4 s +0.0 s
Order form4.3 s +0.9 s
Account panel4.3 s +0.0 s
Trade-ready4.3 s +0.0 s settling

Stack

React with React Router, built with Vite; TradingView chart library plus ECharts; web3 and ethers bundles; Privy and WalletConnect; Sentry.

Delivery

app.txflow.com through Cloudflare over HTTP/3; HTML no-cache; app files cached a year; market data and feed from api.txflow.com.

HostRoleCDN edge seenConnectResponse
app.txflow.compageCloudflare Amsterdam13 ms363 ms
api.txflow.commarket dataCloudflare Amsterdam13 ms254 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.28 sHTML arrives.
0.47–0.79 sweb3 (0.8 MB compressed, 2.8 MB unpacked), index (1.2 MB unpacked) and ethers. The react-router chunk later starts 2.4 s of main-thread work.
0.99 sThe market socket opens; handshake at 1.90 s, 0.9 s later; first message at 2.43 s.
1.32–1.63 sTrade, PositionsModule and ECharts chunks.
1.58–3.50 sAn api.txflow.com request takes 1.9 s.
1.61 sFirst paint.
2.41 sPage header shows the market; order book at 2.65 s.
2.53–3.20 sThe chart library (library.js, 0.9 MB compressed, 6.2 MB unpacked); Privy loads 35 requests from 2.71 s.
3.46–4.36 strading.js (0.5 MB unpacked).
4.36 sPrice shows, 1.7 s after the book.
6.80 sChart drawn, 2.4 s after the price: trade-ready in this load. 22 long tasks took 3.1 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.

Not recorded: an unidentified pop-up covered the chart in both recorded loads (it did not appear during the timed campaign).

Request waterfalldiagnostic capture 1 October, uncached

72 of the 348 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.

PageScriptData requestwaiting for the serverdownloading

0 s0 s1 s1 s2 s2 s3 s3 s4 s4 s5 s5 s6 s6 s1app.txflow.com4 kB316 ms2app.txflow.com/web3-DpA_L…823 kB323 ms3app.txflow.com/ethers-qip…131 kB321 ms4app.txflow.com/index-D12n…488 kB321 ms5app.txflow.com/useReferra…135 kB105 ms6app.txflow.com/Trade-lhQR…256 kB143 ms7app.txflow.com/PositionsM…143 kB304 ms8app.txflow.com/echarts-cf…192 kB303 ms9app.txflow.com406 B1147 ms10explorer-api.walletconnec…175 kB323 ms11api.txflow.com19 kB1928 ms12app.txflow.com/library.0f…914 kB675 ms13privy.app.txflow.com3 kB186 ms14privy.app.txflow.com/main…42 kB1252 ms15privy.app.txflow.com/_app…5 kB1273 ms16privy.app.txflow.com/4547…2 kB1273 ms17privy.app.txflow.com/4e7c…91 kB1279 ms18privy.app.txflow.com/e488…28 kB1276 ms19privy.app.txflow.com/50ad…45 kB1277 ms20privy.app.txflow.com/5256…4 kB1277 ms21privy.app.txflow.com/2275…106 kB1289 ms22privy.app.txflow.com/3833…36 kB1286 ms23privy.app.txflow.com/6538…7 kB1277 ms24privy.app.txflow.com/8038…15 kB1278 ms25privy.app.txflow.com/2637…51 kB1297 ms26privy.app.txflow.com/190-…11 kB1286 ms27privy.app.txflow.com/2869…16 kB1287 ms28privy.app.txflow.com/1093…13 kB1287 ms29privy.app.txflow.com/2231…12 kB1296 ms30privy.app.txflow.com/9404…7 kB1288 ms31privy.app.txflow.com/5106…31 kB1302 ms32privy.app.txflow.com/974-…26 kB1301 ms33privy.app.txflow.com/7361…11 kB1301 ms34privy.app.txflow.com/7969…108 kB1308 ms35privy.app.txflow.com/1110…58 kB1306 ms36privy.app.txflow.com/1928…32 kB1305 ms37privy.app.txflow.com/5187…75 kB1316 ms38privy.app.txflow.com/683-…10 kB1306 ms39privy.app.txflow.com/3185…20 kB1307 ms40privy.app.txflow.com/embe…12 kB1306 ms41privy.app.txflow.com/_bui…9 kB1307 ms42privy.app.txflow.com/_ssg…615 B1316 ms43app.txflow.com/trading.53…125 kB896 ms44api-bridge.txflow.com1 kB1049 ms45arb1.arbitrum.io1 kB1050 ms46api.txflow.com566 B1125 ms47api.txflow.com568 B1132 ms48api.txflow.com598 B1082 ms49api.txflow.com748 B1115 ms50api.txflow.com868 B1119 ms51api.txflow.com581 B1124 ms52api.txflow.com745 B1136 ms53api.txflow.com567 B1123 ms54api.txflow.com961 B1120 ms55api.txflow.com867 B1138 ms56api.txflow.com1 kB1140 ms57api.txflow.com885 B1124 ms58api.txflow.com1 kB1142 ms59api.txflow.com853 B1143 ms60api.txflow.com749 B1118 ms61api.txflow.com773 B1190 ms62api.txflow.com922 B1191 ms63api.txflow.com913 B1191 ms64api.txflow.com783 B1193 ms65api.txflow.com4 kB1194 ms66api.txflow.com667 B1183 ms67api.txflow.com622 B1187 ms68api.txflow.com724 B1189 ms69api.txflow.com547 B1218 ms70api.txflow.com815 B1192 ms71api.txflow.com10 kB1055 ms72api.txflow.com778 B1030 msprice 4.4 sorder book 2.7 schart 6.8 s
Download this figure as an image:

Bottlenecks and fixes, largest firstdiagnostic capture 1 October, uncached

TX-1The react-router chunk starts 2.4 s of main-thread work.grade B
Evidence
1 October capture: 2.4 s of main-thread work starts in react-router-BGcoL_jj.js, one of the two largest such figures in this test; it counts everything that script sets off, not only router code. 22 long tasks add up to 3.1 s before trade-ready. The logged-out follow-up recordings name one concrete part: a function (pt) in the react-router chunk forces layout recalculations of 44 and 38 ms in one recording and 48 ms in the other, and the chart's bottom toolbar another 29 ms.
Gap observed
2.4 s of main-thread work that starts in the react-router chunk
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Record a start-up profile and find what runs from the react-router chunk (route modules imported at start-up are the first thing to check); split it by route. Batch the element-size reads in the function the profile labels pt.
Where
Router configuration and lazy routes.
Verify
DevTools → Performance → Bottom-up: react-router-*.js time.
TX-2The chart is drawn 2.4 s after the price, with a 6.2 MB chart library.grade C
Evidence
1 October capture: chart 2.4 s after the price. library.js is 6.2 MB unpacked; trading.js loads after it; 31 Privy scripts and WalletConnect's 1.2 MB wallet list load in the same window, and the follow-up recordings show Privy's module set-up taking about 100 ms of main thread inside a 250 ms task at 3.5 s, before the price; ECharts is a second chart library on the page. In the warm campaign loads the chart is not the last panel (TX-5).
Gap observed
2.44 s between the price and the chart
Holds back
Chart (median 3.4 s in the timed loads).
Fix
Preload library.js and trading.js with the trade route; drop ECharts from the trade page if TradingView draws the chart; load Privy after the chart.
Where
Trade route entry; wallet provider.
Verify
DevTools → Network: library.js starts before 1.5 s; no privy request before the chart paint.
TX-3In one capture the price showed 1.7 s after the book.grade C
Evidence
1 October capture: first feed message at 2.43 s, book at 2.65 s, price only at 4.36 s, after a 1.9 s api.txflow.com request (1.57–3.50 s). In 10 older timed loads the price and the book show together; in a second set of 10, four loads repeat the gap (0.35 to 0.92 s). So it comes and goes.
Gap observed
1.71 s between the order book and the price
Holds back
Price (median 3.4 s in the timed loads).
Fix
Reproduce the case first; if the price waits for a REST call, render it from the feed's first ticker message.
Where
Price component data source.
Verify
DevTools → Performance: price paint within 200 ms of the first ticker message.
TX-4A pop-up blocked the chart in both recorded loads on 3 October.grade B
Evidence
An unidentified pop-up covered the chart in both diagnostic loads; it did not appear in the timed campaign.
Measured
a chart-covering pop-up in both 3 October diagnostic loads
Holds back
Chart (median 3.4 s in the timed loads).
Fix
Find what puts a layer over the chart on a logged-in load and show it after the trading screen is ready, away from the chart.
Where
Whatever opens the overlay (it was not identified; two logged-out recordings did not show it).
Verify
Reload: no overlay on the chart during the first seconds.
TX-5On a warm reload the order form and positions are the last panels, at 4.3 s, about 0.9 s after the market panels.grade B
Evidence
Warm campaign loads: the order form and the positions panel are last in 3 of 5 loads and tied with the others in 2; the chart is never last alone. The page's main parts are in place at a median 3.4 s, the last panel at 4.3 s and trade-ready at 4.3 s: once the last panel is ready, trade-ready follows at once in 4 of 5 loads. In the 0.9 s in between, the order form fails its check or still shows a placeholder, the positions panel likewise, and the chart is still animating.
Gap observed
0.92 s median between the main parts being in place and trade-ready in the five warm loads; no wait after the last panel
Holds back
The order form and positions panel (last panel median 4.3 s in the timed loads).
Fix
Find what the order form and positions panel wait for after the market panels are shown (account or wallet state), and end the chart's loading animation when its data is in.
Where
Order-form and positions components; the chart panel's loading states.
Verify
DevTools → Performance: the order form and positions fill within 0.3 s of the order book; nothing in the chart animates after the candles appear.
Likely saving
Up to ~0.9 s on trade-ready
TX-6api.txflow.com/info is called 47 times per load, with a round of permission requests first.grade B
Evidence
The 5 older warm timed loads contain 47 or 48 requests to the same /info address each; in one, two of them take 1.0 and 1.3 s and end just before price and book show at 3.88 s. A logged-out follow-up recording shows 23 /info calls with 19 OPTIONS requests (CORS preflights) for that address in the first burst, and /info calls that take over 2 s (1.86–4.09 s). The page is on app.txflow.com and the API on api.txflow.com, so the browser asks permission before the calls. The request bodies are not recorded, so the calls may ask for different things.
Measured
47 requests to one endpoint per load; 19 permission requests for it in the follow-up recording
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Combine the start-up /info calls into a few, and send Access-Control-Max-Age: 7200 on api.txflow.com so the browser remembers the permission, or serve the API under app.txflow.com.
Where
The API client for /info (batching); CORS response headers of api.txflow.com.
Verify
DevTools → Network, filter "info": under 10 requests before the price shows; filter "method:OPTIONS": none on a reload.
Likely saving
Unknown: the slowest /info calls end just before the price shows
TX-7The second feed socket connects, then waits 1.4 s before sending anything.grade C
Evidence
Both logged-out follow-up recordings: the second socket to api.txflow.com completes its handshake at 3.78 s (3.80 s in the other) but sends its first frame only at 5.13 s (5.18 s), 1.35 to 1.38 s later, and receives its first at 5.39 s (5.45 s). The frames are not recorded, so it is not known whether this socket carries the market subscription.
Gap observed
1.35 to 1.38 s between the second socket connecting and its first sent frame, in two recordings
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Find what the second socket waits for before subscribing; if it carries market data, subscribe as soon as it connects, otherwise open it later.
Where
Feed client: the consumer of the second api.txflow.com socket.
Verify
DevTools → Network → WS: the first frame on each socket is sent within 100 ms of the handshake.
Likely saving
Up to ~1.3 s if a trading panel waits for this socket; unknown otherwise

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.

Savings are estimates from the timeline, not measured after a change. They overlap, so they do not add up; the summary gives the combined estimate.

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; 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.