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

Measured from the Netherlands in Chrome, logged out, October 2026.

In short. On a warm reload the screen is trade-ready after 4.0 s (median of 4 loads), 10 of 27 perpetual trading screens, possible rank 7 to 13; after an uncached reload 4.4 s. It was measured logged out, so with fewer panels to load than a logged-in screen. The largest bottleneck: About 12 MB of JSON before the order book shows, 3.1 MB of it for pages the trader is not on. First change to try: Stop prefetching the route data for markets, lend and other instruments before trade-ready, and ask the tickers, markets and assets endpoints only for what the trade page shows.

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: 4 warm and 4 uncached reloads

Warm reloadmedian 4.0 s, range 3.7 s–4.4 s; loads: 4.4 s, 4.1 s, 3.9 s, 3.7 s
Uncached reloadmedian 4.4 s, range 4.1 s–4.9 s; loads: 4.3 s, 4.4 s, 4.9 s, 4.1 s
Standing10 of 27 by median; possible rank 7 to 13. 1.5 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 ready4 of 4 warm, 4 of 4 uncached
Notesmeasured logged out (fewer panels to load); 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.

0 s1 s2 s3 s
Price2.5 s
Order book3.4 s +1.0 s
Order form3.7 s +0.3 s
Chart4.0 s +0.3 s
Trade-ready4.0 s +0.0 s settling

Stack

Next.js, bundled with Turbopack and rendered on the server; TradingView chart library (library.js, chart-widget-gui); Inter font from rsms.me.

Delivery

HTML rendered on the server and cached at CloudFront for 10 minutes (s-maxage=600), a miss in this load; market data from api.backpack.exchange; the chart library is served with max-age=0, while the app's own chunks are immutable for a year. On a warm reload 91 of 303 responses are re-checked with the server.

HostRoleCDN edge seenConnectResponse
backpack.exchangepageCloudFront Amsterdam12 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.47 sHTML starts after a CloudFront miss (server-rendered, 753 KB unpacked). The 3 October recorded load: 0.51 s.
0.63–1.20 sEleven script chunks, up to 1.0 MB unpacked each.
0.99 sPage header shows the market.
1.63 sThe live feed opens; handshake at 2.43 s, 0.8 s later; first message at 2.94 s.
2.17–2.87 sFive api.backpack.exchange responses: 2.7, 2.1, 1.9 and 0.5 MB unpacked, plus 96 KB uncompressed: about 7 MB of JSON.
2.27 sFirst paint.
2.40–2.90 sFive more backpack.exchange responses of about 750 KB unpacked each (3.8 MB together), three of them the same size.
2.71–4.40 sThe chart library (library.js, 2.75 MB unpacked, max-age=0) takes 1.7 s; chart-widget-gui follows at 4.65–5.83 s.
2.91 sPrice shows.
5.01 sOrder book shows, 2.1 s after the feed's first message.
5.91 sChart 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.

WhenWhat
0.5 sHTML arrives
1.3 sFirst market-data request
1.8 sPrice ready
1.8 sFirst frame sent on a live feed
2.2 sFirst frame received on a live feed
3.3 sChart ready
3.8 sOrder book ready
3.8 sOrder form ready
3.8 sTrade-ready

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

Request waterfalldiagnostic capture 1 October, uncached

70 of the 253 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 requestFont, media, other fileStylesheetwaiting for the serverdownloading

0 s0 s1 s1 s2 s2 s3 s3 s4 s4 s5 s5 s1backpack.exchange74 kB385 ms2backpack.exchange/1hyraj9…136 kB530 ms3backpack.exchange/0pkzcvc…217 kB550 ms4backpack.exchange/3llsxo2…305 kB562 ms5backpack.exchange/346owgr…224 kB561 ms6backpack.exchange/0m7hahz…112 kB524 ms7backpack.exchange479 B1101 ms8backpack.exchange479 B1030 ms9backpack.exchange481 B1022 ms10rsms.me/InterVariable.wof…353 kB161 ms11price-indexer.workers.mad…17 kB976 ms12api.backpack.exchange497 B891 ms13api.backpack.exchange3 kB713 ms14api.backpack.exchange854 kB483 ms15api.backpack.exchange5 kB722 ms16api.backpack.exchange497 B880 ms17api.backpack.exchange99 kB687 ms18api.backpack.exchange497 B888 ms19api.backpack.exchange595 kB348 ms20api.backpack.exchange180 kB510 ms21backpack.exchange/7346.a2…32 kB816 ms22backpack.exchange/library…692 kB1691 ms23api.backpack.exchange99 kB919 ms24api.backpack.exchange522 B1095 ms25backpack.exchange/2767.25…2 kB687 ms26backpack.exchange/8732.c6…2 kB942 ms27backpack.exchange/5877.e2…1 kB687 ms28backpack.exchange/2227.e4…46 kB943 ms29backpack.exchange/line-to…14 kB715 ms30backpack.exchange/2157.d1…10 kB703 ms31backpack.exchange/floatin…26 kB726 ms32backpack.exchange/en.6822…1 kB712 ms33backpack.exchange/5546.68…709 B957 ms34backpack.exchange/3762.2e…890 B694 ms35backpack.exchange/302.f0d…2 kB695 ms36backpack.exchange/5075.8c…12 kB710 ms37backpack.exchange/chart-b…13 kB893 ms38backpack.exchange/en.2364…3 kB713 ms39backpack.exchange/1729.0f…1 kB869 ms40backpack.exchange/2153.30…7 kB930 ms41backpack.exchange/5715.5f…6 kB1033 ms42backpack.exchange/chart-w…47 kB1174 ms43backpack.exchange/en.8066…1 kB1003 ms44backpack.exchange/61.6420…2 kB905 ms45backpack.exchange/5458.0a…809 B845 ms46backpack.exchange/8467.68…1 kB904 ms47backpack.exchange/2208.2c…889 B861 ms48backpack.exchange/8596.b8…756 B905 ms49backpack.exchange/1298.d5…4 kB878 ms50backpack.exchange/restric…26 kB928 ms51backpack.exchange/en.8370…734 B704 ms52backpack.exchange/5446.24…2 kB876 ms53backpack.exchange/header-…11 kB877 ms54backpack.exchange/user-de…2 kB921 ms55backpack.exchange/studies…2 kB691 ms56backpack.exchange/4814.8f…1 kB864 ms57backpack.exchange/get-err…6 kB716 ms58backpack.exchange/en.6342…1 kB884 ms59backpack.exchange/6246.3e…1 kB855 ms60backpack.exchange/6625.8e…2 kB812 ms61backpack.exchange/4392.f2…1 kB804 ms62backpack.exchange/7241.[i…846 B854 ms63backpack.exchange/6014.98…9 kB884 ms64backpack.exchange/change-…5 kB952 ms65backpack.exchange/en.1962…2 kB703 ms66backpack.exchange/9796.0e…3 kB851 ms67backpack.exchange/3443.58…4 kB884 ms68backpack.exchange/6408.53…14 kB985 ms69backpack.exchange/drawing…22 kB1121 ms70backpack.exchange933 B692 msprice 2.9 sorder book 5.0 schart 5.9 s
Download this figure as an image:

Bottlenecks and fixes, largest firstdiagnostic capture 1 October, uncached

BP-1About 12 MB of JSON before the order book shows, 3.1 MB of it for pages the trader is not on.grade B
Evidence
1 October capture: seven api.backpack.exchange responses over 45 KB start at 2.17–2.18 s and total 8.1 MB unpacked (the largest 2.7, 2.2 and 1.9 MB; six are compressed and come from the CDN cache with lifetimes of 5 to 600 s). Five route payloads of about 0.8 MB each add 3.8 MB at 2.40–2.90 s. A timed load names the routes: /en/markets.json, /en/lend.json and the trade pages for BTC_USD, BTC_USD_PERP and MU.US_USD_PERP, so four of the five (3.1 MB) are for other pages or markets. It also names the API calls at start-up: /api/v1/tickers, /markets, /assets, /depth and /klines. The order book shows at 5.01 s.
Measured
about 12 MB of JSON before the book appears: 8.1 MB from the API and 3.8 MB of route payloads, 3.1 MB of those for other pages
Holds back
Probably the book (median 3.4 s in the timed loads): the timing points to it, but the captures do not show that this panel waits for it.
Fix
Stop prefetching the route data for markets, lend and other instruments before trade-ready, and ask the tickers, markets and assets endpoints only for what the trade page shows.
Where
Next.js link prefetching for /_next/data/…/en/*.json; the callers of /api/v1/tickers, /markets and /assets.
Verify
DevTools → Network, filter "_next/data": one route payload before the book shows; total JSON before the book under 3 MB.
BP-2The order book shows 2.1 s after the feed delivers, and the depth snapshot is requested twice.grade C
Evidence
1 October capture: socket to ws.backpack.exchange created at 1.63 s, connected at 2.43 s, first message at 2.94 s; book at 5.01 s. All 20 older timed loads request api.backpack.exchange/api/v1/depth twice with the same address. The requests take 0.25 to 1.1 s; in one load 0.9 s each (2.84–3.73 s, then 3.82–4.73 s, with the book at 5.22 s), and the 3 October recording shows a similar pair (1.31–2.21 s and 2.36–3.32 s, book at 3.78 s). In those two loads the second depth request ends about 0.5 s before the book shows. In the campaign the warm medians are price 2.5 s, book 3.4 s, order form 3.7 s and chart 4.0 s; the order form is the last panel in 2 of the 4 warm loads.
Gap observed
2.07 s between the first feed message and the order book
Holds back
Book (median 3.4 s in the timed loads).
Fix
Request the depth snapshot once, at the same time as the socket is opened, and check why /api/v1/depth sometimes takes about 1 s; draw the book when the first snapshot is in.
Where
Order-book start-up: the two callers of /api/v1/depth and the depth endpoint itself.
Verify
DevTools → Network, filter "depth": one request, started before 1.5 s; book paint within 200 ms of its response.
BP-3The chart library is revalidated on every visit and takes 1.7 s.grade B
Evidence
1 October capture: library.8fdacc60e5256d6fcc84.js (2.8 MB unpacked, 0.7 MB compressed) is served with "public, max-age=0" and was a CDN miss, taking 1.7 s (2.70–4.40 s); chart-widget-gui then takes another 1.2 s; chart at 5.91 s. The app's own chunks are served with max-age=31536000, immutable, so only the chart files have this problem. In the campaign the chart is last in all 4 uncached loads and in 2 of the 4 warm ones.
Gap observed
1.7 s for library.js and 1.2 s for chart-widget-gui
Holds back
Chart (median 4.0 s in the timed loads).
Fix
Serve the TradingView files with content hashes and max-age=31536000, immutable, and preload library.js on the trade route.
Where
Static asset headers for /charting_library/.
Verify
DevTools → Network: library.js from disk cache on reload.
BP-4The HTML waits 0.5 s for the server.grade B
Evidence
474 ms to the first byte on 1 October, 480 ms on 3 October. The page already has s-maxage=600 with stale-while-revalidate, but was a CloudFront miss in the capture.
Gap observed
0.47 s to the HTML first byte on 1 October; 0.48 s on 3 October
Holds back
Every panel: nothing is shown before this ends.
Fix
Find why the trade page misses the CloudFront cache despite s-maxage=600 (per-user cookies or query strings in the cache key are the usual cause), or serve a static shell.
Where
CloudFront cache key and policy for the trade route; Next.js route caching.
Verify
DevTools → Network → document: x-cache Hit, under 100 ms.
BP-5A 353 KB font is loaded from a third-party site.grade B
Evidence
1 October capture: InterVariable.woff2 from rsms.me, 353 KB, requested at 2.03 s (2.03–2.19 s). It needs its own connection to another host and is the whole variable font.
Measured
one 353 KB font from a third-party host
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Host a subset of Inter on the app's own domain and preload it.
Where
The @font-face rule that points at rsms.me.
Verify
DevTools → Network, filter "woff2": the font comes from the app's own host and is under 100 KB.
Likely saving
Small on a reload; about 0.3 MB and one extra connection less on a first visit
BP-6Scripts keep arriving in late waves, also when cached.grade C
Evidence
1 October capture: 147 script requests, with groups of 27 at 4.5 s and 26 at 5.5 s after the first 78. 3 October warm recording: 66 between 3.5 and 4.0 s, of which 53 start before the order book is ready at 3.78 s. All 10 timed loads show the same early and late groups. One warm task still blocks for 275 ms at 1.03 s.
Measured
two late groups of about 26 script requests each
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Preload the chunks of the later waves on the trade route, or bundle them with the first group.
Where
Bundler chunking for the trade route; the HTML head.
Verify
DevTools → Network, filter JS: no new group of script requests after 2 s.
Likely saving
Unknown

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: 4 warm and 4 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.