Why HTML-only scraping fails on SPAs
A single-page app (SPA) sends a near-empty HTML shell - the real content is built in the browser by JavaScript that fetches data from an API and writes it into the page (the DOM, the browser's live model of the page). A plain HTTP fetch only downloads that first shell; it never runs the JavaScript, so it sees the empty placeholder, not the content. To scrape these sites you have to run the JavaScript, wait for the page updates to finish, and only then grab the HTML. That is exactly what a JS-rendering scraping API does for you.
What to look for
Pick an API that uses a real browser engine (Chromium, Firefox), not a lightweight JS shim that only fakes parts of a browser. Look for configurable wait strategies - wait for a CSS selector to appear, wait for network activity to go quiet ("network idle"), or wait for a custom JavaScript check of your own to pass. You also want support for scrolling and clicking to trigger lazy-loaded content (content that only loads as you reach it), plus per-request proxy and fingerprint control. Network capture is a bonus: it lets you grab the underlying XHR data (the background API calls the page makes) directly, which is often cleaner than re-extracting it from rendered HTML. Finally, watch cost transparency - JS rendering costs more than a plain HTML fetch, so you want to render only when needed.
When NOT to use a rendering API
If the SPA pulls its data from a JSON endpoint you can spot, calling that endpoint directly is faster, cheaper, and more reliable than rendering the whole page. Open the browser's network tab, find the XHR (the background request) that returns the data, and replicate it yourself. Rendering is the fallback for when that endpoint is encrypted, signed, or otherwise too awkward to call directly.
