Coinbase TradingView: 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 8.0 s (median of 5 loads), 27 of 27 perpetual trading screens, rank 27 is the only one the measurements leave open; after an uncached reload 9.1 s. The largest bottleneck: The price appears about 4.7 s after the live feed delivers. First change to try: Draw the price, book and order form once their own code and the first feed message are in; do not wait for the rest of the app. Likely saving if fixed: About 4–5 s faster on a warm reload, from 8.0 s to roughly 3–3.5 s, mostly by cutting the code-loading waves before the trading panels draw (CBT-1, CBT-2).
Defect found: Coinbase: the chart keeps the old market's name after a switch. You switch from BTC Perp to ETH Perp. The page title, the address and the candle prices all change to ETH, but the chart's legend still says BTC_USDC-PERPETUAL. It stays wrong while you remain on the page. Details below.

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 8.0 s, range 7.7 s–8.4 s; loads: 8.0 s, 8.0 s, 7.7 s, 8.4 s, 7.8 s
Uncached reloadmedian 9.1 s, range 8.9 s–9.5 s; loads: 9.5 s, 8.9 s, 9.1 s, 9.0 s, 9.3 s
Standing27 of 27 by median; rank 27 is the only one the measurements leave open. 5.6 s behind the fastest, Thalex (2.4 s): 3.3 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
Notesorder 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.

0 s1 s2 s3 s4 s5 s6 s7 s8 s
Price6.9 s
Order book6.9 s +0.0 s
Order form6.9 s +0.0 s
Chart7.2 s +0.2 s
Account panel7.6 s +0.4 s
Trade-ready8.0 s +0.4 s settling

Stack

React app split into over a thousand small chunks (c_*.js); TradingView charting library from static-assets.coinbase.com; OneTrust banner; Google Pay script.

Delivery

www.coinbase.com through Cloudflare over HTTP/2 with long-lived cached app files; market data from Coinbase (drb.coinbase.com, ws-retail) and Deribit (www.deribit.com, history.deribit.com), Coinbase's derivatives exchange.

HostRoleCDN edge seenConnectResponse
www.coinbase.compageCloudflare Amsterdam12 ms110 ms
api.coinbase.commarket dataCloudflare Amsterdam12 ms15 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.16 sHTML arrives.
0.31–0.71 sapp-shell.js (0.7 MB compressed, 3.4 MB unpacked) and boot scripts; 1.6 s of main-thread work later starts in c_boot-vendor.
1.79–2.97 sA 5.1 MB (unpacked; 117 KB compressed) response from www.deribit.com marked no-store, and four no-store responses from www.coinbase.com of 1.1, 0.5, 0.4 and 0.3 MB.
1.82–2.45 sThe live feeds open (ws-retail, streams.drb, drb.coinbase.com); first messages at 2.45–2.93 s.
1.82–8.54 sOne www.coinbase.com request stays open for 6.7 s.
2.1–7.5 sChunk after chunk: c_CO0lZDQN.js (1.0 MB compressed, 5.4 MB unpacked) at 2.13 s, then dozens more until 7.5 s; 1,298 requests to www.coinbase.com in total before trade-ready.
9.43 sPrice shows (the order book is not separately detectable in this capture).
9.73 sThe chart library (library.js, 2.8 MB unpacked) is requested; trading.js at 10.22 s.
11.65 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.2 sHTML arrives
1.3 sFirst frame sent on a live feed
1.4 sFirst frame received on a live feed
6.1 sPrice ready
6.1 sOrder book ready
6.1 sOrder form ready
7.3 sChart ready
7.3 sAccount panel ready
7.5 sTrade-ready

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

Request waterfalldiagnostic capture 1 October, uncached

71 of the 1500 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 filewaiting for the serverdownloading

0 s0 s1 s1 s2 s2 s3 s3 s4 s4 s5 s5 s6 s6 s7 s7 s8 s8 s9 s9 s10 s10 s11 s11 s1www.coinbase.com6 kB26 ms2www.coinbase.com/app-shel…716 kB404 ms3www.deribit.com117 kB1174 ms4www.coinbase.com70 kB1131 ms5www.coinbase.com6713 ms6www.coinbase.com/a_RAxmqt…275 kB83 ms7api.coinbase.com852 B1153 ms8www.coinbase.com/c_CO0lZD…1.0 MB252 ms9www.coinbase.comopen10www.coinbase.com527 B1275 ms11login.coinbase.com1 kB1214 ms12www.coinbase.comopen13www.coinbase.com1 kB1022 ms14www.coinbase.comopen15cdn.cookielaw.org/otBanne…132 kB100 ms16www.coinbase.com/c_Fbj2LB…137 kB125 ms17www.coinbase.comopen18www.coinbase.com/c_DJvjbR…106 kB493 ms19www.coinbase.com/c_DJwp1o…405 kB873 ms20www.coinbase.com/c_DRnsuz…941 B1079 ms21www.coinbase.com/c_I6BfE5…2 kB1052 ms22www.coinbase.com/c_icEDKo…785 B1053 ms23www.coinbase.com/c_DGII0x…1 kB1055 ms24www.coinbase.com/c_B8Lym6…2 kB1055 ms25www.coinbase.com/c_Ce1xIR…940 B1053 ms26www.coinbase.com/c_BdwBOh…2 kB988 ms27www.coinbase.com/c_oepKdJ…2 kB989 ms28www.coinbase.com/c_xPWZk1…796 B989 ms29www.coinbase.com/c_BLtSim…1 kB994 ms30www.coinbase.com/c_gQKk9Q…2 kB999 ms31www.coinbase.com/c_DSAcWB…978 B993 ms32www.coinbase.com/c_B1JkPN…922 B996 ms33www.coinbase.com/c_BrCiTn…1 kB996 ms34www.coinbase.com/c_D0iTvc…3 kB996 ms35www.coinbase.com/c_CkQ1Xl…2 kB996 ms36www.coinbase.com/c_CiMetu…782 B998 ms37www.coinbase.com/c_ZU0SjJ…1 kB999 ms38www.coinbase.com/c_DdDeQG…2 kB1011 ms39www.coinbase.com/c_DN0C2G…2 kB1000 ms40www.coinbase.com/c_9u34Rr…1 kB999 ms41www.coinbase.com/c_CbRTB3…1 kB1010 ms42www.coinbase.com/c_BBAU9x…1 kB1000 ms43www.coinbase.com/c_iT6ry6…1 kB1000 ms44www.coinbase.com/c_BNdnmy…1 kB1010 ms45www.coinbase.com/c_Dj22Eg…3 kB1009 ms46www.coinbase.com/c_C1JrO6…1 kB1014 ms47www.coinbase.com/c_J3Y5mB…6 kB1014 ms48www.coinbase.com/c_qQT4Vb…6 kB1019 ms49www.coinbase.com/c_DnZPnJ…1 kB1020 ms50www.coinbase.com/c_DloXlH…6 kB1009 ms51www.coinbase.com/c_C5Dg07…12 kB1019 ms52www.coinbase.com/c_C-SAte…944 B1020 ms53www.coinbase.com/c_T2fnpI…16 kB1023 ms54www.coinbase.com/c_CUe5tt…857 B1020 ms55www.coinbase.com/c_UlKtXy…869 B1021 ms56www.coinbase.com/c_lVu2iy…1 kB1019 ms57www.coinbase.com/c_Dqc42i…1 kB1025 ms58www.coinbase.com/c_BY18XO…1 kB1025 ms59www.coinbase.com/c_oLW0XA…3 kB1023 ms60www.coinbase.com/c_BgXD6C…1 kB1024 ms61www.coinbase.com/c_C9QCw0…2 kB1021 ms62www.coinbase.com/c_DQoKrm…3 kB1022 ms63www.coinbase.com/c_X63pnp…2 kB1019 ms64www.coinbase.com/c_2nVh4f…1 kB1021 ms65www.coinbase.com/c_CCEr6f…971 B1019 ms66www.coinbase.com/c_UlwjAf…1 kB1011 ms67pay.google.com6 kB475 ms68www.coinbase.com30 kB1067 ms69www.coinbase.comopen70static-assets.coinbase.co…670 kB242 ms71static-assets.coinbase.co…125 kB535 msprice 9.4 schart 11.6 s
Download this figure as an image:

Bottlenecks and fixes, largest firstdiagnostic capture 1 October, uncached

CBT-1The price appears about 4.7 s after the live feed delivers.grade C
Evidence
3 October recorded warm reload: first feed message at 1.4 s, price at 6.1 s. In between, the app loads its code files in waves (CBT-2). Coinbase's servers answer the 88 data requests in a median 0.13 s, so the wait is in the page, not the servers. 1 October uncached capture: first live messages at 2.45 s, price at 9.43 s.
Gap observed
4.7 s between the first feed message and the price, in the 3 October recording
Holds back
Price (median 6.9 s in the timed loads).
Fix
Draw the price, book and order form once their own code and the first feed message are in; do not wait for the rest of the app.
Where
Trading route start-up: the modules the trading panels wait for.
Verify
DevTools → Performance: price paint within 200 ms of the first ticker message.
Likely saving
Up to ~4 s, together with CBT-2
CBT-2About 1,260 code files load in waves before anything is usable, even from the browser cache.grade B
Evidence
3 October recorded warm reload: 1,258 script requests before the first panel, 1,242 of all 1,261 from the browser cache, in bursts from 1.0 to 4.4 s and again at 5.5 s. 1 October uncached capture: 1,298 requests to www.coinbase.com and 143 to static-assets.coinbase.com before trade-ready; script chunks keep arriving until 7.5 s. 1 October timed loads (same page, SPCX market): 1,204 to 1,214 script requests before trade-ready in all 8 loads that completed, with a last wave of several hundred files between 4.5 and 6 s; the largest are c_B_WsmIIU.js (5.5 MB unpacked) at 1.66 s and c_DgywP-YC.js (1.4 MB) at 5.11 s.
Gap observed
4.5 s between the start of the first script burst and the start of the last one
Holds back
Every panel: nothing is shown before this ends.
Fix
Build one bundle (or a handful) for the perpetuals route, so the files of the late wave at 4.5–6 s are requested at the start. Until then, list the route's chunks as modulepreload links in the HTML so the browser fetches them in one go.
Where
Bundler chunking (the c_*.js split) and the perpetuals route's imports; the HTML head for the preload links.
Verify
DevTools → Network, filter JS: under 100 script requests before the price, and no new wave of script requests after 2 s.
Likely saving
Part of the ~4 s in CBT-1; more on a first visit
CBT-3About 7 MB (unpacked) of uncacheable JSON on every load: the full Deribit instrument list and five product-list requests.grade B
Evidence
1 October uncached capture: www.deribit.com answers with 5.1 MB unpacked (117 KB compressed), cache-control "no-store, public, max-age=10", at 1.79–2.97 s; four no-store responses from www.coinbase.com of 1.1, 0.5, 0.4 and 0.3 MB run alongside. Compressed, the five together are only 250 KB, so the cost is parsing, not download. The 1 October timed loads (same page, SPCX market) name them: /api/v2/public/get_instruments on www.deribit.com, and /api/v3/brokerage/products on www.coinbase.com, requested 5 times within 0.4 s. The names come from a different load than the sizes and headers, matched by order and size.
Gap observed
1.2 s for the Deribit response
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Call get_instruments with the currency and kind the page shows, not the full list. Merge the five /api/v3/brokerage/products requests into one that returns only the perpetuals. Give both a cache lifetime of minutes: the Deribit response already says max-age=10 but no-store cancels it.
Where
The get_instruments call to www.deribit.com and its cache-control header; the product-list loader behind /api/v3/brokerage/products.
Verify
DevTools → Network, filter "get_instruments" and "brokerage/products": one request each, under 100 KB unpacked, or "(disk cache)" on a normal reload.
Likely saving
Not separable from the start-up wait: about 7 MB less JSON to parse on every load
CBT-4The chart library is requested only after the price shows.grade C
Evidence
1 October uncached capture: library.js (2.8 MB unpacked) at 9.73 s and trading.js at 10.22 s, after the price at 9.43 s; chart drawn at 11.65 s. In the warm campaign loads the account panel, not the chart, is the last panel in all 5. Both files are cached for only 2 hours (max-age=7200), the app's own files for a year. 1 October timed loads (same page, SPCX market): the candle request (get_tradingview_chart_data) is sent at 1.29 s and again at 1.82 s, and the chart settings (user_chart_config) are requested 4 times, at 4.33, 4.54, 6.68 and 7.93 s.
Gap observed
0.30 s between the price and the chart-library request
Holds back
Chart (median 7.2 s in the timed loads).
Fix
Add modulepreload links for library.js and trading.js on the perpetuals route, request user_chart_config once, and give the chart library the same one-year cache lifetime as the app files (its file names carry a content hash).
Where
Perpetuals route entry and HTML head; chart widget loader; cache-control for static-assets.coinbase.com chart files.
Verify
DevTools → Network: library.js starts before 3 s; one user_chart_config request; library.js shows max-age=31536000.
Likely saving
~0.2 s on a warm reload (chart 0.24 s after the price); more on a first visit
CBT-5The chart can show the wrong market after a switch.grade B
Evidence
See defect card CB-1: after switching to ETH the chart keeps the BTC symbol.
Measured
a retained BTC chart symbol after switching to ETH
Holds back
The chart, which shows the wrong market; no load time is involved.
Fix
See defect card CB-1.
Where
Saved-layout restore.
Verify
activeChart().symbol() equals the page market after a switch.
Likely saving
None: a correctness fix
CBT-624 GraphQL requests and 15 analytics requests are spread over the load, most of them before the price.grade C
Evidence
1 October timed loads (same page, SPCX market): 24 requests to www.coinbase.com/graphql/query between 0.68 and 6.94 s, 11 to as.coinbase.com/amp and 4 to as.coinbase.com/metrics, all before trade-ready at 7.95 s; 22 of the GraphQL requests and all 15 analytics requests start before the price shows at 6.75 s. Which of the GraphQL requests the trading panels wait for is not visible from outside.
Measured
24 GraphQL and 15 analytics requests before trade-ready; 22 and 15 before the price
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Combine the GraphQL queries the trading page needs into one request sent at start-up, and send analytics after trade-ready.
Where
The GraphQL client (batching) and the as.coinbase.com analytics client.
Verify
DevTools → Network, filter "graphql": 5 or fewer requests before the price; filter "as.coinbase.com": none before the price.
Likely saving
Unknown: it depends on which queries the panels wait for
CBT-7The consent banner and Google Pay load before the price shows.grade B
Evidence
1 October uncached capture: OneTrust otSDKStub.js at 3.55 s and otBannerSdk.js (0.5 MB unpacked) at 4.55 s; pay.google.com/pay.js (0.24 MB unpacked) at 7.05 s, followed by five www.gstatic.com scripts (0.33 MB unpacked) at 7.97–8.75 s; the price shows at 9.43 s. OneTrust's own main-thread cost is small (about 8 ms in the 3 October recording).
Measured
about 1.1 MB of consent-banner and Google Pay script before the price
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Load the consent banner and pay.js after trade-ready, and pay.js only where a payment can be made.
Where
The OneTrust loader (otSDKStub.js) and the Google Pay loader.
Verify
DevTools → Network, filter "cookielaw", "pay.google" and "gstatic": no requests before the price shows.
Likely saving
Small: about 1.1 MB less script before the price
CBT-8Coinbase rejects some of its own start-up requests with HTTP 429, and the page keeps retrying.grade B
Evidence
1 October timed loads (same page, SPCX market): in 2 of the 8 loads that completed, coinbase.app_picker.AppPickerService/GetApplicationsV2 is answered with HTTP 429 (too many requests) 6 times, about once a second; /session, /err-reports and a second request for the page itself also get 429. The 3 October recorded reload has 11 responses with HTTP 429 between 1.3 and 6.3 s. These loads were made minutes apart by our test, so a normal visitor may see this less often.
Measured
6 rejected GetApplicationsV2 requests per load, in 2 of 8 loads
Holds back
Not established: the captures do not show which panel waits for this.
Fix
On HTTP 429, wait for the Retry-After time and back off instead of retrying every second; check why a normal page load reaches the rate limit.
Where
The AppPickerService client and the rate-limit rules for /session and the page route.
Verify
DevTools → Network, filter "status-code:429": none during a page load; after a forced 429, retries are spaced out.
Likely saving
None measured on trade-ready
CBT-9Scripts force the browser to recalculate layout 70 times during the load.grade C
Evidence
3 October recorded warm load: 70 forced layout recalculations costing 124 ms in total. The logged-out follow-up recording names the callers: the largest, 78 ms at 1.74 s, is inside function A of assets/sw-cache/e_CxV4naul.js, and a 33 ms one at 2.85 s is inside the chart's chart-bottom-toolbar.js. The same recording shows a 158 ms task at 0.98 s in which about 47 ms is spent inserting elements into the page (appendChild) from e_CxV4naul.js, which looks like the loader that adds each code chunk to the page.
Measured
70 forced layout recalculations, 124 ms, in the recorded load
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Batch the geometry reads and DOM writes in e_CxV4naul.js and the chart toolbar so the browser lays out once; check whether the chunk loader inserts elements one by one.
Where
e_CxV4naul.js (the function the profile labels A) and chart-bottom-toolbar.js.
Verify
DevTools → Performance: no "forced reflow" warnings during the load; the chunk loader's task under 50 ms.
Likely saving
Up to ~0.2 s of main thread
CBT-10The chart library starts up with a 170 ms blocking task and loads optional dialogs and toolbars at once.grade C
Evidence
Logged-out follow-up recording: a 170 ms task at 2.26 s, of which 107 ms is sampled inside the TradingView module runtime (runtime.1f6691a05496db116913.js, function r). The runtime then requests optional chart parts during start-up, among them change-interval-dialog.js at 2.61 s and drawing-toolbar.js at 2.61 s. This recording has no trade-ready time, so no panel delay is assigned.
Measured
a 170 ms task in the chart runtime; optional chart chunks requested at start-up
Holds back
Not established: the captures do not show which panel waits for this.
Fix
Load the chart's dialogs and drawing toolbar on first use instead of at start-up, and look at what the module runtime initialises in that 170 ms.
Where
TradingView library set-up: the runtime's module loader and the chart's initial feature set.
Verify
DevTools → Network, filter "dialog" and "toolbar": no chart dialog or toolbar chunks before the candles are drawn; Performance: no task over 100 ms from the chart runtime.
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.

Defects

CB-1Coinbase: the chart keeps the old market's name after a switch
What you see
You switch from BTC Perp to ETH Perp. The page title, the address and the candle prices all change to ETH, but the chart's legend still says BTC_USDC-PERPETUAL. It stays wrong while you remain on the page.
Why
The chart layout saved for the ETH market contains BTC as its symbol. Every visit to ETH loads that saved layout and does not set the chart back to the market of the page, and every later autosave writes the wrong symbol back.
What it breaks
The chart lies about which market it shows. Anything inside the chart that relies on its symbol, such as drawings or alerts, can attach to the wrong market without the trader noticing.
Fix
After loading a saved layout, set the chart to the page's market and check that it took effect. Do not save a layout while the chart's symbol and the page's market disagree.
Still unknown
How the wrong layout was first saved; the likeliest cause is a save racing a market switch. Whether other market pairs are affected.
Technical detail
Reproduction in the DevTools console on the ETH Perp page (top context): [location.pathname, document.querySelector('iframe[name^="tradingview_"]').contentWindow.tradingViewApi.activeChart().symbol()] returns ['/advanced-trade/perpetuals/ETH_USDC-PERPETUAL', 'BTC_USDC-PERPETUAL']. Measured on 2 October 2026: the legend title read BTC_USDC-PERPETUAL at 0, 2, 5 and 10 s after the switch while its O/H/L/C values were at ETH's price level. Evidence: bench/out/session4-coinbase-chart-api/2026-10-02T03-00-32-132Z/result.json and the Coinbase chart-symbol map in .scratch/coinbase-chart-symbol/.

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.