Question: I'm a n00b with Dash and I'm trying to update a DashTable from websocket feeds. The code appears to work when there aren't too many feeds, but once there are, Chrome starts spamming my server with fetch requests (from dash_update_component) Is there any way to make this more performant ? import dash_bootstrap_components as dbc import dash_core_components as dcc import dash_html_components as html import json import pandas as pd from dash import callback, Dash, dash_table from dash.dependencies import Input, Output, State from dash_extensions import WebSocket symbols = ["BTCUSDT"] columns = ["symbol", "bid_volume", "bid_price", "ask_volume", "ask_price"] def create_data(): data = {} for col in columns: if col == "symbol": data[col] = symbols else: data[col] = [None] * len(symbols) return data df = pd.DataFrame(data=create_data()) # Create example app. app = Dash(prevent_initial_callbacks=True) app.layout = html.Div([ dash_table.DataTable(df.to_dict('records'), [{"name": i, "id": i} for i in df.columns], id='tbl', editable=True), dcc.Input(id="input", autoComplete="off"), html.Div(id="message"), WebSocket(url="wss://fstream.binance.com/ws/", id="ws") ]) # Write to websocket. @app.callback(Output("ws", "send"), [Input("input", "value")]) def send(value): sub_msg = { "method": "SUBSCRIBE", "params": [], "id": 1 } for ins in symbols: sub_msg["params"] += ([f"{ins.lower()}@bookTicker"]) return json.dumps(sub_msg, indent=0) # Read from websocket. @app.callback(Output('tbl', 'data'), [Input("ws", "message")]) def on_feed(message): if "data" not in message: return dash.no_update else: data = json.loads(message["data"]) print(data) symbol = data["s"] row_idx = df.index[df['symbol'] == symbol].tolist()[0] df.loc[row_idx, columns] = [symbol, data["B"], data["b"], data["a"], data["A"]] return df.to_dict('records') if __name__ == '__main__': app.run_server(debug=True)  

Answer: One thing you can do to improve performance is to convert your callbacks into clientside callbacks: symbols = ["ETHBUSD", "BNBUSDT", "BTCUSDT"] # ... app.clientside_callback( """ function(value) { const symbols = ['ETHBUSD', 'BTCUSDT', 'BNBUSDT'] const subMsg = { 'method': 'SUBSCRIBE', 'params': [], 'id': 1 }; for (const ins of symbols) { subMsg.params.push(`${ins.toLowerCase()}@bookTicker`); } return JSON.stringify(subMsg); } """, Output("ws", "send"), Input("input", "value"), prevent_initial_call=True ) app.clientside_callback( """ function(message, tableData) { if (message === undefined) { return window.dash_clientside.no_update; } data = JSON.parse(message['data']); if (data === undefined) { return window.dash_clientside.no_update; } const newTableData = tableData; row = newTableData.find(row => row.symbol === data['s']); if (row !== undefined) { row['bid_volume'] = data['B']; row['bid_price'] = data['b']; row['ask_volume'] = data['a']; row['ask_price'] = data['A']; } return tableData; } """, Output("tbl", "data"), Input("ws", "message"), State("tbl", "data"), prevent_initial_call=True )   Clientside callbacks execute your code in the client in JavaScript rather than on the server in Python.  https://dash.plotly.com/performance If you look at the network tab you can see that no websocket related requests are made anymore now. In this case we're still updating the table for every valid message coming in. You might also want to limit this by using a dcc.Interval: dcc.Interval(id="interval", interval=500) # interval fires every 500 ms # ... app.clientside_callback( """ function(nIntervals, message, tableData) { if (message === undefined) { return window.dash_clientside.no_update; } data = JSON.parse(message['data']); if (data === undefined) { return window.dash_clientside.no_update; } const newTableData = tableData; row = newTableData.find(row => row.symbol === data['s']); if (row !== undefined) { row['bid_volume'] = data['B']; row['bid_price'] = data['b']; row['ask_volume'] = data['a']; row['ask_price'] = data['A']; } return tableData; } """, Output("tbl", "data"), Input("interval", "n_intervals"), State("ws", "message"), State("tbl", "data"), prevent_initial_call=True )  You can experiment with adjusting the interval. A lower interval makes result are more "real time"/accurate, but a higher interval means less updates that need to be performed.