Single-page application (SPA)

What is a Single-Page Application

A single-page application is a web app that loads a single HTML page and dynamically updates content via JavaScript without full page reloads.

A single-page application (SPA) is a web application that loads a single HTML page and updates the content dynamically as the user interacts with the app. Instead of loading entire new pages from the server, SPAs use JavaScript to rewrite the current page in place. This creates a smoother, faster user experience similar to native desktop or mobile applications.

When you click a link in a traditional website, the browser discards the current page and loads a completely new one from the server. In an SPA, the browser stays on the same page while JavaScript fetches new data and updates only the parts of the screen that changed. The URL in the address bar updates via the History API, but no full page reload occurs.

How SPAs work

When a user visits an SPA, the server sends a minimal HTML shell with a JavaScript bundle. The JavaScript then:

  1. Renders the initial view, often showing a loading spinner or skeleton screen
  2. Handles navigation via the browser’s History API (changing the URL without reloading)
  3. Fetches data from APIs as needed, typically as JSON
  4. Updates the DOM to reflect new content based on the fetched data
  5. Manages state, caching, and client-side routing rules

Popular SPA frameworks include React, Vue, Angular, Svelte, and Solid. Each provides tools for component-based UI development, state management, and client-side routing.

SPA vs traditional multi-page application

Multi-page applicationSingle-page application
Each navigation loads a new HTML documentNavigation updates content via JavaScript
Simpler initial render, no JS requiredRequires JavaScript to display any content
SEO-friendly by defaultNeeds server-side rendering or prerendering for SEO
Full page reloads between viewsInstant transitions, app-like feel
Server handles routingClient handles routing
Simpler caching and CDN setupMay need complex cache invalidation strategies
Lower initial JavaScript payloadLarge initial bundle to download

Many modern sites are not pure SPAs or pure MPAs. They use hybrid approaches like Next.js, Nuxt, or SvelteKit that combine server-side rendering with client-side hydration for the best of both worlds.

SEO challenges with SPAs

SPAs present unique challenges for search engines and crawlers:

  • Empty initial HTML - The first load may contain only a <div id="root"></div> with no content. Search engines that do not render JavaScript see nothing.
  • JavaScript-dependent content - Headings, links, and text only appear after scripts run. If the crawler does not wait for rendering, it misses the content.
  • Client-side routing - URL changes do not correspond to actual server requests. The crawler must intercept and follow these virtual routes.
  • Delayed rendering - Content may load in stages, making it hard to know when the page is “complete”. A product description might load in 200ms while reviews load in 800ms.
  • Meta tag updates - Title and description tags may be set by JavaScript after the initial HTML arrives. Static crawlers see the generic shell tags instead of the page-specific ones.
  • Lazy-loaded images - Images that load only when scrolled into view may be missing from a crawler snapshot.

To address these issues, SPA developers often use server-side rendering (SSR), static site generation (SSG), or prerendering to serve meaningful HTML to crawlers. Frameworks like Next.js and Nuxt make SSR relatively straightforward by running the same components on the server.

SPA framework detection

Crawler tools and site profilers look for signatures of SPA frameworks in the HTML:

  • React: data-reactroot, __NEXT_DATA__, or _reactListening
  • Vue: data-v- attributes or __VUE__ global
  • Angular: ng-app, ng-version, or angular in script filenames
  • Svelte: svelte- classes or __svelte in the DOM
  • Generic: High script-to-text ratio, empty body with a single mount point div

These signals help crawlers decide whether to enable JavaScript rendering before attempting to extract content.

How crawler.sh handles SPAs

crawler.sh is designed to crawl SPAs effectively. Its JavaScript rendering engine executes the site’s JavaScript and waits for the DOM to stabilize before extracting content. The site profiler detects SPA frameworks automatically by looking for the markers above and enables JS rendering when needed.

The crawler also:

  • Follows client-side routes by intercepting history.pushState and history.replaceState calls
  • Extracts links from the rendered DOM, not just the initial HTML, so client-side navigation paths are discovered
  • Records the final URL after client-side navigation, even if the server initially returned a 200 for the shell page
  • Captures titles, descriptions, and headings that are set by JavaScript after the initial load
  • Applies appropriate drain time budgets so content that loads asynchronously has time to appear

For SPAs that use hash-based routing (/#/products), the crawler treats the hash as part of the unique URL and processes each route separately.

Crawler.sh - Free Local AEO & SEO Spider and a Markdown content extractor | Product Hunt