BTSE: 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 7.0 s (median of 5 loads), 25 of 27 perpetual trading screens, possible rank 24 to 25; after an uncached reload 7.0 s. The largest bottleneck: The market feed sends its first frame only at 4.1 s, after three rounds of API requests. First change to try: Send initialMarketData, inquire/market and the socket subscription first. Move country/all, informationFromIp, regulatoryDisclaimer/banner, languages and tracking events until after the price shows, and request typesPrice once. Likely saving if fixed: About 3 s faster on a warm reload, from 7.0 s to about 4 s, with BT-1, BT-2, BT-4 and BT-5; reaching 2.5–3 s also needs BT-3.

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 7.0 s, range 6.8 s–7.2 s; loads: 7.2 s, 7.2 s, 6.9 s, 7.0 s, 6.8 s
Uncached reloadmedian 7.0 s, range 6.6 s–7.3 s; loads: 7.3 s, 7.0 s, 6.9 s, 6.6 s, 7.3 s
Standing25 of 27 by median; possible rank 24 to 25. 4.6 s behind the fastest, Thalex (2.4 s): 2.9 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: outside viewport

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 s6 s7 s
Order form5.1 s
Account panel5.1 s +0.0 s
Price5.2 s +0.1 s
Order book5.2 s +0.0 s
Chart5.9 s +0.7 s
Trade-ready7.0 s +1.1 s settling

Stack

Not captured on 1 October; from the 3 October recorded warm load only.

Delivery

www.btse.com through CloudFront.

HostRoleCDN edge seenConnectResponse
www.btse.compageCloudFront Amsterdam13 ms35 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 orderrecorded warm reload 3 October

From one warm reload recorded with Chrome's performance trace on 3 October 2026. Recording slows the page, so read the order and the gaps, not the totals. Some host names were masked when the recording was saved.

WhenWhat
0.79 sHTML arrives, among the slowest in the test.
1.67–2.69 sAbout 20 API requests go out together; each waits 0.7–1.0 s for the server.
2.92–4.13 sTwo more rounds of API requests; the last one finishes at 4.13 s.
3.45 sOrder form and wallet panel show.
4.14 sThe page sends its first frame on the market socket (ws.btse.com), right after the last API round; first message at 4.37 s.
4.80 sPrice and order book show.
5.88 sChart drawn.
6.92 sTrade-ready in the recorded load. Long tasks before the first panel: 1.5 s, the longest 575 ms.

Request waterfallrecorded warm reload 3 October

62 of the 369 requests (the page itself, the longest and the largest) started before trade-ready in the warm reload recorded on 3 October, 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 s1www.btse.com556 B779 ms2host masked99 kB56 ms3host masked2 kB263 ms4host masked2 kB756 ms5host masked136 B744 ms6host masked26 kB1013 ms7host masked605 B752 ms8host masked2 kB819 ms9host masked462 B803 ms10host masked300 B770 ms11host masked7 kB818 ms12host masked214 B763 ms13host masked30 kB1004 ms14host masked11 kB967 ms15host masked246 B725 ms16host masked265 B751 ms17host masked140 B753 ms18host masked5 kB738 ms19host masked344 B809 ms20host masked143 B755 ms21host masked527 B805 ms22host masked3 kB720 ms23host masked183 B264 ms24host masked209 B267 ms25host masked238 B293 ms26host masked245 B271 ms27host masked187 B266 ms28host masked313 B303 ms29host masked275 B272 ms30host masked776 B268 ms31host masked302 B273 ms32host masked254 B263 ms33host masked299 B281 ms34host masked12 kB270 ms35host masked342 B269 ms36host masked227 B265 ms37host masked3 kB268 ms38host masked529 B300 ms39host masked5 kB275 ms40host masked630 B264 ms41host masked19 kB507 ms42host masked24 kB501 ms43host masked33 kB510 ms44host masked65 kB775 ms45host masked328 B264 ms46host masked143 B542 ms47host masked1 ms48host masked244 B262 ms49host masked175 B265 ms50host masked740 B265 ms51host masked2 kB303 ms52host masked3 kB270 ms53host masked17 kB486 ms54host masked · trades196 B264 ms55host masked795 B269 ms56host masked238 B308 ms57host masked323 B263 ms58host masked313 B309 ms59host masked1 kB265 ms60host masked · trades11 kB267 ms61host masked2 kB269 ms62host masked · trades29 kB527 msprice 4.8 sorder book 4.8 schart 5.9 s
Download this figure as an image:

Bottlenecks and fixes, largest firstrecorded warm reload 3 October

BT-1The market feed sends its first frame only at 4.1 s, after three rounds of API requests.grade C
Evidence
Recorded load: about 20 requests go out at 1.67 s and each waits 0.7–1.0 s for the server; more rounds follow at 2.9 s and 3.35 s. The last one finishes at 4.13 s and the market socket sends its first frame at 4.14 s; price and book follow at 4.80 s. In the campaign the order form and wallet show at 3.3 to 3.4 s and price and book not before 4.9 s. Logged-out recording with a fresh browser profile, 3 October, which keeps the addresses: the first round mixes the market requests (futures/api/inquire/initialMarketData, futures/api/inquire/market, futures/api/config/marketCategory) with requests the trading panels do not need first (api/country/all, which takes 1.48 s, api/informationFromIp, api/regulatoryDisclaimer/banner, api/languages, tracking/api/v1/events); a later round fetches futures/api/inquire/initial/market (1.2 MB unpacked), futures/api/v2.3/market/risk_limit (0.3 MB) and api/init/typesPrice twice.
Gap observed
2.47 s from the first API batch to the market-socket subscription
Holds back
Price (median 5.2 s in the timed loads), book (median 5.2 s in the timed loads).
Fix
Send initialMarketData, inquire/market and the socket subscription first. Move country/all, informationFromIp, regulatoryDisclaimer/banner, languages and tracking events until after the price shows, and request typesPrice once.
Where
Feed client start-up and the start-up request sequence.
Verify
DevTools → Network → WS: first frame sent before 1 s. DevTools → Network, filter "api.btse.com": the market requests are the first ones.
Likely saving
~1.5 s
BT-2The HTML takes 0.8 s.grade B
Evidence
788 ms to the first byte of the document in the recorded load, 833 ms in the logged-out recording. There the response says cache-control "public, max-age=60, s-maxage=604800" with age 244994 (2.8 days) and "x-cache: Error from cloudfront": the CDN is set up to keep the page for 7 days, but reports an error and still takes 0.8 s. That pattern fits a CDN that tries the origin, fails and falls back to its stored copy; the recording does not prove it.
Gap observed
0.788 s to the document first byte
Holds back
Every panel: nothing is shown before this ends.
Fix
Look up why CloudFront reports "Error from cloudfront" for the futures page and fix the origin or the error handling, so the edge answers from its stored copy without waiting for the origin.
Where
CloudFront distribution for www.btse.com: origin health and the cache behaviour of the futures page.
Verify
DevTools → Network → document → Headers: "x-cache: Hit from cloudfront"; Timing: waiting for server response under 100 ms.
Likely saving
~0.7 s
BT-31.5 s of long main-thread tasks before the first panel.grade B
Evidence
8 long tasks, the longest 575 ms at 1.73 s, before the order form shows at 3.45 s. The browser attributes the longest one to BTSE's own scripts. The largest start-up scripts, by name from the logged-out recording: fTPyrBIP.js (3.5 MB unpacked), B-0vxubZ.js (2.0 MB), BOOzV_OZ.js (1.3 MB), app.DI3xhnWo.js (1.0 MB) and chunk-echarts.K2WzvGbX.js (0.65 MB), all requested in the first 1.5 s.
Gap observed
1.5 s of main-thread time before the first panel
Holds back
Every panel: nothing is shown before this ends.
Fix
Profile start-up and split the 575 ms task; check whether chunk-echarts (0.65 MB) and the non-trading parts of fTPyrBIP.js are needed before the first panel, and load them later if not.
Where
Bundler output for the futures page.
Verify
DevTools → Performance: no task over 200 ms before the first panel.
Likely saving
Up to ~1 s more, after BT-1
BT-4Trade-ready comes 1.1 s after the last panel has its data: the chart is still animating.grade B
Evidence
All 10 campaign loads: between the last panel and trade-ready the only readiness condition failing is an animation running in the chart panel, for 0.62 to 1.22 s on the warm loads (medians: last panel 5.9 s, trade-ready 7.0 s). Recorded load: 1.05 s, with 15 animated elements in the chart; the panels do not move, fonts are loaded and no image is pending.
Gap observed
0.62 to 1.22 s between the last panel 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 ~1 s
BT-5The chart is drawn 0.7 s after price and book.grade C
Evidence
Campaign warm medians: price and book 5.2 s, chart 5.9 s; recorded load: 4.80 s and 5.88 s. Logged-out recording: the chart library (charting_library/bundles/library.8fdacc60e5256d6fcc84.js, 2.8 MB unpacked) is requested at 6.19 s, after the price at 5.47 s, and /chart/markets/list is requested twice at 6.18 s, taking 0.55 and 0.97 s.
Gap observed
0.7 s between the price and book median and the chart median (two separate medians, not a wait measured inside one load)
Holds back
Chart (median 5.9 s in the timed loads).
Fix
Request library.js and chart/markets/list together with the first market requests, not after the price.
Where
Chart component loading.
Verify
DevTools → Network, filter "charting_library": library.js starts before 2 s.
Likely saving
~0.7 s
BT-6For a first-time visitor, a device-check script blocks the page for over 2 s.grade B
Evidence
Logged-out recording with a fresh browser profile, 3 October: wsdk.js from webdevicejs.com, loaded by a BTSE script (B-0vxubZ.js) at 1.7 s, runs inside one 2.32 s task from 2.39 to 4.71 s; sampled profiling places the time in wsdk.js itself. While it runs, 15 API responses that had arrived by 2.9 s are not handed to the page until about 5.0 s, and the futures socket created at 1.86 s completes its handshake only at 4.99 s. The price shows at 5.5 s. In the logged-in recording, all third-party scripts together used 0.5 s, so the timed screen does not pay this.
Gap observed
2.3 s of main-thread time in the fresh-profile device-check task
Holds back
Start-up as a whole; which panel waits for this work is not established.
Fix
Load the device check after the trading screen is usable, or only before the actions that need it, such as sign-in and orders.
Where
The wsdk.js loader in B-0vxubZ.js (called from app.DI3xhnWo.js).
Verify
DevTools → Performance in a new browser profile: no wsdk.js task before the price shows.
Likely saving
Over 2 s, first visits only
BT-7API requests are preceded by a permission request, adding about 0.3 s per round.grade C
Evidence
The page is on www.btse.com and the API on api.btse.com, so the browser first sends an OPTIONS request (a CORS preflight) for each address. Logged-out recording with a fresh browser profile, 3 October: 26 OPTIONS requests in all; 16 at 2.10–2.25 s take 0.26 to 0.54 s each before the real requests can be sent, and 6 more at 5.42 s take 0.25 s each. The logged-in recording masks request methods, so it does not show whether a returning visitor pays the same.
Gap observed
0.26 to 0.54 s for each permission request before the real request can be sent
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Send Access-Control-Max-Age: 7200 on api.btse.com so the browser remembers the permission, or serve the API under www.btse.com so no permission request is needed.
Where
CORS response headers of api.btse.com, or the routing of /api under www.btse.com.
Verify
DevTools → Network, filter "method:OPTIONS": none on a reload.
Likely saving
About 0.3 s per API round; the market data needs up to three rounds
BT-8A 1.1 MB translation file is re-checked on every load, and the fonts use an old format.grade B
Evidence
Logged-out recording: www.btse.com/i18n/en.json is 1.1 MB unpacked (274 KB compressed) with cache-control "no-cache", so the browser asks the server about it on every load, while the scripts and styles are cached for a year. Four .woff fonts of about 120 KB each are cached for one day; the newer woff2 format is typically about 30% smaller.
Measured
a 1.1 MB translation file marked no-cache and four fonts of about 120 KB
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Give en.json a content hash in its name and the same one-year lifetime as the scripts; ship the fonts as woff2.
Where
Build output for /i18n and /static/font; their cache-control headers.
Verify
DevTools → Network: en.json and the fonts show "(disk cache)" on a reload; font type woff2.
Likely saving
Small on a reload; about 0.1 MB less on a first visit
BT-9Advertising and tag scripts are requested in the first 1.4 s.grade C
Evidence
Logged-out recording: pixel.mediamathrdrt.com/scripts/cg_btse.js and coinzillatag.com/lib/performance.js at 0.84 s, googletagmanager.com/gtm.js at 1.39 s, all before any trading panel. The recording shows no completed response for the coinzilla and Tag Manager scripts. Their main-thread cost was not measured.
Measured
three advertising and tag scripts in the first 1.4 s
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Load the advertising and tag scripts after trade-ready.
Where
The script tags for mediamath, coinzilla and Google Tag Manager.
Verify
DevTools → Network, filter "mediamath", "coinzilla", "googletagmanager": no requests before the price shows.
Likely saving
Not measured
BT-10Scripts force the browser to recalculate layout 538 times during a warm reload.grade B
Evidence
3 October recorded warm load: 538 forced layout recalculations costing 399 ms in total, the most of any screen in this test. The recording masks the callers. The logged-out follow-up recording does not reproduce it (41 small ones), so it belongs to the logged-in screen with its account panels.
Measured
538 forced layout recalculations, 399 ms, in the recorded warm load
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Find the code that reads element sizes right after writing to the DOM (DevTools → Performance flags each one as a forced reflow) and batch the reads.
Where
The components of the logged-in futures screen that measure themselves while rendering.
Verify
DevTools → Performance on a logged-in reload: forced-reflow warnings under 50, total under 50 ms.
Likely saving
Up to ~0.4 s of main thread on a warm reload
BT-11A 0.75 s blocking task spent setting and clearing timers through the error-reporting wrapper.grade C
Evidence
Logged-out follow-up recording: one task of 752 ms at 7.26 s, before the order book shows at 9.60 s in that load. The CPU profile places 582 ms of it in setTimeout and 84 ms in clearTimeout; every sampled setTimeout call runs through the Sentry wrapper in chunk-sentry.DKA24Cnk.js and Vue component set-up in B-0vxubZ.js, and the clearTimeout calls come from tooltip code in fTPyrBIP.js (clearTooltipTimer, destroyToolTip). So the page creates and destroys a very large number of tooltip timers while its components mount, and each one is wrapped by Sentry.
Measured
a 752 ms task, 666 ms of it in setTimeout and clearTimeout, in the follow-up recording
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Count how many tooltip components mount at start-up and give them one shared timer; turn off Sentry's timer instrumentation if it is not needed.
Where
The tooltip component in fTPyrBIP.js and the Sentry integration (setTimeout wrapping) in chunk-sentry.js.
Verify
DevTools → Performance: no task over 200 ms attributed to setTimeout or clearTimeout.
Likely saving
Up to ~0.7 s on a first visit; unknown on a warm reload

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.