- Evidence
- 1 October capture: library.0f032f79907a36608fbe_v1.js (4.9 MB unpacked, 0.8 MB compressed) is requested at 3.70 s, 1.0 s after the book at 2.75 s; chart drawn at 5.29 s. In the campaign the chart is the last panel in the warm loads (median 2.9 s). A timed warm load shows the two candle requests starting later still: /x-api/contract/v5/public/instrument/kline/market at 4.00 s and /kline/mark at 4.09 s, with the chart ready at 4.20 s, 34 ms after the second one ends.
- Gap observed
- 1.0 s between the order book and the chart library request
- Holds back
- Chart (median 2.9 s in the timed loads).
- Fix
- Preload library.js when the trading route is matched, and send the two candle requests (kline/market and kline/mark) with the first market requests, not after the library has loaded.
- Where
- Trading route entry; chart widget loader and datafeed.
- Verify
- DevTools → Network: library.js starts before 1.5 s; filter "kline": both requests start before 2 s.
Bybit: where its trading screen loses time, and what to fix
Measured from the Netherlands in Chrome, logged out, October 2026.
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 reload | median 3.9 s, range 3.8 s–4.3 s; loads: 4.3 s, 3.8 s, 3.9 s, 4.0 s, 3.9 s |
| Uncached reload | median 4.7 s, range 4.4 s–9.3 s; loads: 4.7 s, 4.4 s, 9.3 s, 4.8 s, 4.7 s |
| Standing | 9 of 27 by median; possible rank 7 to 11. 1.4 s behind the fastest, Thalex (2.4 s): 1.6 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 ready | 5 of 5 warm, 5 of 5 uncached |
| Notes | measured logged out (fewer panels to load); order book or trades drawn as a picture; checked as drawn and updating, values not read; recent 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.
Stack
React 18.2; TradingView chart library (library.js, the largest in this test); unversioned "latest" scripts (data-core, by-vendors, header, antiPhishingCode); AppsFlyer, an A/B-test service and Google sign-in.
Delivery
www.bybit.com over HTTP/3 (OpenResty); HTML cached 60 s; hashed app files cached a year; unversioned "latest" scripts cached for 60–300 s; market data over one socket to ws2.bybit.com.
| Host | Role | CDN edge seen | Connect | Response |
|---|---|---|---|---|
| www.bybit.com | page | — | 13 ms | 23 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.
| When | What |
|---|---|
| 0.07 s | HTML arrives. |
| 0.21–0.55 s | main.js (2.4 MB unpacked), vendor-biz (0.9 MB), data-core.latest, by-vendors.latest; react.18.2 later starts 1.04 s of main-thread work. |
| 0.72 s | First paint. |
| 1.09 s | The market socket opens; handshake at 1.64 s; first message at 2.14 s. |
| 1.71–1.90 s | header.latest.js (617 KB unpacked) and antiPhishingCode.latest.js (328 KB unpacked). |
| 1.75–3.02 s | A/B-test requests to sc-abtest…de take 1.3 s. |
| 2.75 s | Order book shows; price at 3.24 s. |
| 3.70 s | The chart library is requested: library.js, 0.8 MB compressed, 4.8 MB unpacked. |
| 3.78 s | Google sign-in script (268 KB unpacked). |
| 5.29 s | Chart drawn: trade-ready in this load. |
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.
| When | What |
|---|---|
| 0.0 s | HTML arrives |
| 2.8 s | Price ready |
| 2.8 s | asks ready |
| 2.8 s | bids ready |
| 2.8 s | Order form ready |
| 2.8 s | positions ready |
| 2.8 s | First market-data request |
| 3.0 s | Chart ready |
| 3.9 s | Trade-ready |
279 requests before trade-ready; 10 long main-thread tasks (over 50 ms) before trade-ready, longest 182 ms; 116 script requests before the first panel; 0 requests over HTTP/1.1.
Request waterfalldiagnostic capture 1 October, uncached
65 of the 262 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.
PageScriptStylesheetData requestwaiting for the serverdownloading
Bottlenecks and fixes, largest firstdiagnostic capture 1 October, uncached
- Evidence
- 1 October capture: ten "latest" scripts have max-age=60 (header, antiPhishingCode, by-vendors, by-globals, monitor, globalPopup, complianceWall, campaign, googleOneTap, ada) and data-core.latest.min.js has 300 s; the largest are header (0.6 MB unpacked), antiPhishingCode (0.3 MB) and data-core (0.2 MB). The hashed app files next to them are cached for a year. A trader who returns after more than a minute has to re-check these with the server; within a minute they come from cache (the 3 October warm reload re-checked only 1 of 279 responses).
- Measured
- cache lifetimes of 60 s for ten scripts and 300 s for one
- Holds back
- Not established: the captures do not show which panel waits for this.
- Fix
- Version the "latest" scripts by content hash and cache them for a year, like the hashed app files.
- Where
- Build output and CDN rules for *.latest.js and *.latest.min.js.
- Verify
- DevTools → Network → Headers on header.latest.js: max-age=31536000.
- Evidence
- 1 October capture: two A/B-test calls take 1.3 s each (1.75–3.02 s); AppsFlyer scripts at 0.59 and 1.04 s; googleOneTap.latest.js at 3.21 s and Google's account script (0.3 MB unpacked) at 3.78 s, all before the chart is drawn at 5.29 s. In a timed warm load the A/B-test calls (/api/v2/abtest/online/results) take only 0.19 s, so the 1.3 s is not constant. Whether the chart waits for any of these is not shown.
- Gap observed
- 1.3 s for the A/B-test calls
- Holds back
- Probably the chart (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
- Load A/B testing, AppsFlyer and Google sign-in after the chart is drawn.
- Where
- Tag loading in the trading page.
- Verify
- DevTools → Network: no sc-abtest, appsflyer or accounts.google.com request before the first chart paint.
- Evidence
- All 5 warm campaign loads: between the chart having its data and trade-ready (0.89 to 1.18 s, median 0.95 s) the only readiness condition failing is an animation running in the chart panel. Recorded load: 0.85 s, 9 of 10 samples. Nothing moves and no font or image is pending.
- Gap observed
- 0.95 s median between the chart and trade-ready in the five warm loads
- Holds back
- Trade-ready itself: the page counts as ready only when nothing in a panel is still animating or loading.
- Fix
- Record a reload with DevTools → Animations and find what still animates in the chart after the candles are drawn, for example a toolbar loading spinner or a fade-in; end it when the data is in.
- Where
- The chart panel and its loading states.
- Verify
- DevTools → Animations during a reload: nothing in the chart container animates after the candles appear.
- Likely saving
- Up to ~0.9 s
- Evidence
- Campaign, uncached round 4: the chart had its data at 3.59 s, but the bid side of the order book failed its check in 57 of the next 58 samples and trade-ready came only at 9.29 s. The other 4 uncached loads did not show it. The records do not show a failed request.
- Gap observed
- 5.7 s with the bid side of the order book failing its check, in one uncached load
- Holds back
- The order book, in 1 of 10 timed loads.
- Fix
- Check the order book for a state where the bid side empties or re-renders after the first snapshot.
- Where
- Order-book component and its feed subscription on ws2.bybit.com.
- Verify
- Reload 20 times with the cache disabled: the bid side stays filled once it has appeared.
- Likely saving
- None on the median; aimed at a rare 5.7 s stall
- Evidence
- Timed loads: /common-static/fhs/i18n-upload/low-cache/project/release/common/en.json (237 KB unpacked, 70 KB compressed) is requested twice, 0.3 s apart (0.64 and 0.98 s uncached, both downloaded; 0.71 and 1.05 s warm, both from cache). /x-api/v3/config/web is fetched seven times before trade-ready on the uncached load (from 1.40 to 4.64 s) and four times on the warm one. /x-api/spot/api/basic/symbol_list_v3, the spot symbol list (169 KB unpacked), takes 0.56 to 0.66 s on the perpetuals page.
- Measured
- one translation file requested twice and one configuration address up to seven times per load
- Holds back
- Not established: the captures do not show which panel waits for this.
- Fix
- Share one request for the common translation file and one for config/web; load the spot symbol list only where spot markets are shown.
- Where
- The callers of common/en.json and /x-api/v3/config/web; the caller of symbol_list_v3.
- Verify
- DevTools → Network, filter "common/en.json" and "config/web": one request each.
- Likely saving
- Small
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.