Unreal Engine Web Build Gradually Loses Performance When Loading Large Data Sets From My Website API

Hi All,

I am working on an Unreal Engine project that connects to my website to retrieve and display dynamic information inside an interactive experience, and I am running into a performance problem that I have not been able to diagnose properly. The project needs to request data from a backend API, process the returned information, and update the interface while the user continues interacting with the application. The initial loading process works as expected, and the data is displayed correctly when the application first starts. However, after the application has been running for a while and several data requests have been completed, the experience gradually becomes less responsive. Interface elements take longer to update, some interactions feel delayed, and the application occasionally pauses briefly when new information arrives from the website. The issue is most noticeable when the application has to process a larger response containing multiple records rather than a small amount of data. I have been trying to determine whether the slowdown is caused by the way I handle HTTP responses in Unreal Engine, the amount of data being processed on the game thread, or some other part of the communication between the application and my backend.

The problem is difficult to reproduce consistently because the application does not become slow immediately after startup. During the first few requests, the API responses are received and displayed without any obvious performance issues, but repeated requests over a longer session seem to make the application progressively less responsive. I have checked whether the website is returning unusually large responses, and I am also reviewing how the application handles the data after each request completes. The backend returns structured JSON containing the information required by the application, and the client parses that response before updating the relevant interface elements and gameplay-related data. My concern is that even though the network request itself completes successfully, processing the response or repeatedly creating and updating objects may be introducing additional work that accumulates over time. I have not yet established whether the delay occurs while waiting for the server, parsing the JSON, converting values into Unreal data structures, or updating the interface. Because the symptoms appear after multiple successful requests rather than during the initial connection, I would like to identify a reliable way to measure each stage instead of assuming that the website API is responsible for the entire performance problem.

I have already started reviewing the programming logic responsible for sending requests and processing their results. The application uses Unreal Engine’s HTTP functionality to communicate with the backend, and I am checking whether requests are being created too frequently or whether previous request objects, response references, delegates, or related data are being retained longer than necessary. I am also examining whether the same interface components are being updated repeatedly when a response arrives, even when only a small portion of the displayed information has changed. One area I am particularly concerned about is whether JSON parsing and the subsequent processing of a large response are happening on the game thread, because that could explain why the interface briefly freezes when a request returns a substantial amount of data. At the same time, I do not want to move processing into background tasks without understanding which operations are safe to perform outside the game thread and which Unreal Engine objects must only be accessed from the game thread. I would appreciate advice on the recommended architecture for handling larger API responses in Unreal Engine while keeping the application responsive and avoiding unnecessary allocations or repeated processing.

Another aspect I am investigating is whether the slowdown is related to memory usage or repeated object creation during the application’s session. Each response may contain multiple records that need to be converted into structures or used to update existing objects, and I want to make sure that old data is properly released or reused when it is no longer needed. If the application continually creates new objects or retains references to previous responses, memory consumption could increase gradually and potentially contribute to the pauses I am observing. However, I have not confirmed that a memory leak exists, and I do not want to confuse normal memory allocation with an actual retention problem. I would like to know which Unreal Engine profiling tools would be most useful for comparing memory usage, game-thread timing, and frame performance before and after repeated API requests. I am also interested in understanding how to identify whether the cost comes from JSON deserialization, container operations, Blueprint execution, UI updates, or another part of the request-handling pipeline. A clear profiling method would help me determine whether the problem is caused by inefficient code, excessive work triggered by incoming data, or an accumulation of resources that should have been cleaned up.

I have also considered whether the way the application is packaged and executed could influence the behavior, because my goal is to provide a stable interactive experience rather than one that works well only during development. The application communicates with the same backend service, but performance can be difficult to evaluate accurately when comparing editor testing with a packaged build. I want to avoid making assumptions based on editor performance alone, especially if the packaged version handles timing, memory, or rendering differently. My current priority is to capture useful performance measurements during a session that begins normally and then becomes slower as more API responses are processed. Ideally, I would like to record request duration, response size, parsing time, time spent updating application objects, frame-time changes, and memory usage so that I can correlate the slowdown with a particular stage. If Unreal Engine provides a recommended way to profile asynchronous HTTP callbacks and their downstream processing, I would appreciate pointers to the relevant tools or documentation. I am especially interested in learning how to keep network communication asynchronous without accidentally moving expensive processing back onto the game thread or introducing synchronization problems when the returned data is used by gameplay and interface systems.

Has anyone encountered a similar situation in Unreal Engine where an application initially handles website API requests correctly but gradually becomes less responsive after processing repeated or relatively large JSON responses? I would appreciate suggestions for identifying the exact source of the slowdown and improving the request-processing architecture without changing unrelated parts of the project. If useful, I can provide a simplified example of the request code, the JSON parsing logic, the way the response is passed to the interface, and profiling results from a session where the performance gradually deteriorates. I would also like to know whether there are common mistakes involving HTTP request lifetimes, delegate handling, JSON deserialization, game-thread work, or object references that could produce this type of behavior. My goal is to establish whether the problem is primarily CPU processing, memory retention, or excessive interface updates and then make a targeted correction based on measurable evidence. Any recommendations for a systematic debugging process using Unreal Engine’s built-in profiling tools would be very helpful.

Fine at startup, then a hitch each time a larger JSON body arrives, is almost always the game thread allocating and rebuilding UI, not the HTTP wait itself.

The complete callback (VaRest or the HTTP module) runs on the game thread. Parsing a big payload and turning every record into new objects will stall exactly when the response lands. Log the time at the start and end of that callback. If the gap grows with the payload, parse off the game thread and only apply the finished data on the game thread.

The “gets worse the longer it runs” part is usually accumulation. If each request appends widgets or array entries and nothing clears the previous set, the UObject count and the Slate tree grow forever. obj list and stat slat will climb in step with the slowdown. Clear or reuse the array. Use a ListView or TileView with one entry widget instead of constructing a button per record, and Set Text on the rows that changed instead of rebuilding the whole tree.

Drop the previous request when the next one starts: unbind the complete delegate and release the JSON DOM. Holding every past response pins those strings. On an HTML5 package the same leak grows the wasm heap, and that heap does not shrink, so it shows up sooner there.

stat unit while it degrades. If Game spikes on arrival and GPU does not, it is the callback. If both stay flat until the callback, it is the socket. Also page the API (limit and offset) so one response is a page, not the whole table.

The request finishing is not the part that hitches. HTTP is already async. The callback, the JSON parse, and the widget or actor updates all run on the game thread unless you moved them. Fine for the first few calls, then worse, and worse on a big payload, is accumulation on that thread. Not the socket.

Split it before you change the architecture. In the callback, log three times with FPlatformTime::Seconds: when the response bytes arrive, when deserialize returns, and when the UI refresh returns. Then take one Unreal Insights capture across a session that starts fine and ends slow. Launch with -trace=cpu,frame,bookmark. That works on a packaged build, so you are not judging this from the editor. Drop a bookmark at the start of the callback. If the game-thread spike sits inside FJsonSerializer::Deserialize, it is the parse. If it sits after that, it is your update.

The part that gets worse over time is retention, so watch counts, not just frame time. Run stat uobjects and stat memory at request 1 and again around request 30. If the UObject count or the widget count climbs by about the number of records each response, you are creating them and keeping them. The usual versions: appending each response onto the previous TArray instead of emptying it, Create Widget plus Add to Viewport per record with no Remove from Parent, or storing the raw JSON string in an array that never shrinks. A hitch that stays the same size is a fat parse. A hitch that grows is something you did not release.

What is safe off the game thread is turning the JSON string into a plain struct array. No UObject, no UMG, no actor, no Slate in there. Do that on the thread pool, then AsyncTask back to the game thread to apply it. UObject and widget calls have to stay on the game thread. Keep a single request in flight and cancel the previous one when a new one starts. On the game thread, update the widgets you already have. Do not rebuild the whole list unless the record count changed.

That is the split: request time, parse time, apply time, and whether memory and UObject counts climb. Fix whichever of those four actually grows. You do not need to restructure the rest of the project to see it.

Thanks for the detailed explanation. The distinction between the initial hitch caused by JSON parsing and the gradual slowdown caused by accumulated widgets or retained response data makes sense. I hadn’t considered that rebuilding the entire UI for every response could cause the Slate tree and UObject count to keep growing over time. Measuring the callback duration and comparing it with stat unit should help narrow things down before I start changing the request-handling logic. I’m also interested in the suggestion to parse the JSON off the game thread. If I move that work to a background task, what is the safest way to pass the parsed data back to the game thread without accessing UObjects from the background thread? Would using plain C++ structures for the intermediate data and updating the existing widgets only after parsing finishes be a good approach here?