The Virto Commerce storefront is built as a Single Page Application (SPA) (Vue.js), which means the browser loads one main index.html
and then dynamically renders pages (catalog, products, CMS content, etc.) via GraphQL as the user navigates.
In practice, the load balancer and static content server are configured so that all static files (JavaScript bundles, CSS, images, robots.txt
, sitemaps
, etc.) are served directly. If a request matches a file, that file is returned (or a 404 if not found); but any other URL (such as a “folder” or page route) is routed to index.html
with an HTTP 200 response.
The SPA client then reads the path (using the HTML5 History API) and fetches the correct data to display (products, categories, pages, etc.). This setup preserves clean, shareable URLs: for example, a URL like /category/widgets
can be copied or refreshed and the SPA will load the widgets category page.
Note: Google’s SEO best practices recommend using the History API for SPAs so that each view has its own real URL.
*Figure: Virto Commerce SPA frontend architecture. A client request goes to the load balancer, which serves static assets or proxies the request to index.html
*for client-side routing.
Prerender Seamlessly Renders JavaScript for Faster Indexing *sits in front of search bots to provide a pre-rendered HTML version.
The diagram above illustrates this flow. All client requests for resources (scripts, styles, images) are handled directly, while requests for content routes (categories, products, pages, etc.) return the SPA shell (index.html
), letting the Vue app render the page in the browser.
This design gives typical SPA advantages: fast in-app navigation, deep-linking support, and the ability to bookmark or share any page. Because Virto uses “history mode” routing, each page URL looks like a normal link, which search engines and users prefer. The client-side code then uses GraphQL APIs to fetch data and build the page on the fly.
SEO-Friendly Rendering
A challenge with SPAs is that crawlers may not execute JavaScript, so they could see little content. To solve this, Virto integrates Prerender Seamlessly Renders JavaScript for Faster Indexing (dynamic rendering) for SEO. A reverse-proxy (e.g. Nginx) sits in front of the storefront: when a known bot or crawler (Googlebot, Facebook, Twitter, etc.) requests a page, Prerender Seamlessly Renders JavaScript for Faster Indexing intercepts and returns a fully rendered HTML snapshot of that page.
In other words, search engines see a “server-side rendered” version, while normal users get the client-side SPA. This hybrid approach delivers the best of both worlds: crawlers see meaningful HTML content (page titles, meta tags, product info), and users still enjoy a fast single-page experience. As the Virto docs note, Prerender Seamlessly Renders JavaScript for Faster Indexing generates pre-rendered HTML snapshots for SPAs, significantly improving SEO-friendliness and Web Vitals metrics.
Dynamic rendering via Prerender is also simpler to set up than a full SSR framework. Prerender’s own blog explains that it provides static HTML to bots and dynamic JavaScript to users, making it a cost-effective alternative to building custom SSR.
404 Pages and Soft Errors
Because Virto always serves index.html
(even for unknown URLs), the HTTP status code is 200 for every request. If the client-side router cannot match a URL, the SPA app displays the site’s 404 page (the CMS page with slug /404
). However, that error page is a “soft 404”: the browser shows an error message, but the server has already sent a 200 OK status. This is a common SPA behaviour.
It ensures the user sees an error page (and can navigate from it), but from the server’s point of view, the request was fulfilled. Google’s documentation warns that this makes “soft 404” errors – pages that say “not found” in content but return 200 – which can confuse crawlers.
Indeed, Prerender Seamlessly Renders JavaScript for Faster Indexing emphasizes the difference between soft vs. hard 404s: “Soft 404 pages return a 200 HTTP status code and show a message about a nonexistent page. Hard 404 pages have the same content, however, they also have a 404 HTTP status”. Knowledgebase - Prerender. Only true 404s (hard errors) will be skipped or penalised by bots.
Virto’s current SPA setup can’t immediately send a 404 status from the server for a missing route, because that would break the SPA flow. (The load balancer simply forwarded the request to the app). In practice, when a page isn’t found the SPA shows the 404 content, but Googlebot still sees a 200 response – something Google calls a soft 404.
Google suggests workarounds: for example, after determining content is missing, use a client redirect to a dedicated error URL that does return 404 (for instance, /not-found
handled by the server) or add a noindex
meta tag on the error page.
Virto Cloud implements custom HTTP code (Under development), for example, configure an Nginx rule so that /not-found
yields a 404 status.
In most cases, however, the SPA’s 404 page will eventually be crawled as an error page: Google will index it as “not found” content and typically de-prioritize it. The key point is that the server response code is 200 and the frontend logic triggers the 404 content – a trade-off noted in Google’s SPA SEO guidelines.
Detecting and Fixing Broken Links
Even with prerendering and SPA routing, broken or outdated links can harm SEO. Virto provides ways to catch these issues. First, the platform has Google Analytics 4 integration that can track page visits, including 404 pages. GA4 automatically logs pageviews, and if your 404 page has a unique title (e.g. “Page not found”), you can use GA4’s Engagement reports to find how often it was hit.
In practice, you’d filter GA4 by the 404 page’s title or URL, revealing which missing-URL users (or bots) tried to access. Analytics Mania and MeasureSchool have guides on using GA4 for 404 tracking that explain this in detail.
Beyond GA4, Virto includes a Broken Links management tool ( Under development)* in the admin. This tool logs any 404 hits and lets the team mark each one for action. For example, you can ignore harmless 404s, or set up 301/302 redirects. Virto supports internal redirects (redirecting to another page in the store) or external redirects. There’s also an option to use load balancer (or CDN) rules: for certain legacy URLs you can force a real HTTP 404 instead of letting the SPA catch it, if needed for SEO or compliance. In short, the workflow is: track broken links via GA4, review them in the tool, and then either ignore, redirect to a new URL, or explicitly return a 404 status. This flexibility helps marketing teams fix SEO issues without changing code.
Alignment with Best Practices
Overall, Virto’s SPA frontend aligns with current SEO best practices for modern sites. By using clean URLs (History API) and ensuring every page is reachable at a unique path, it meets Google’s recommendation to avoid hash-based routes. By integrating a pre-rendering service, it gives crawlers HTML content to index without sacrificing user experience. The SPA’s fallback to a 200-status index page is a known compromise, but Google explicitly acknowledges this pattern and suggests mitigating it via redirects or noindex tags. With GA4 and Virto’s broken-links tool, teams have visibility into “soft 404s” and can correct them through redirects (which is actually recommended over leaving soft 404s) or by adjusting their content.
Virto’s frontend serves static files directly and routes all other requests through the SPA (index.html), giving smooth in-app navigation and shareable deep links. Prerender Seamlessly Renders JavaScript for Faster Indexing is used to intercept bots and serve SEO-friendly HTML snapshots. Unresolved URLs still return 200+SPA 404 content (a soft 404) by default, but tools like GA4 tracking and the built-in Broken Links manager help teams detect and handle these cases (via redirects or ignore rules). This architecture strikes a balance between an app-like storefront and SEO needs, following guidelines from Google and SEO experts.
Resources and Further Reading
- Virto Commerce documentation on Frontend SPA architecture and prerender integration docs.virtocommerce.org.
- Prerender Seamlessly Renders JavaScript for Faster Indexing blog: *How to Optimise SPAs for SEO (covers fallback routing, prerendering benefits, etc.).
- Google Search Central: JavaScript SEO Basics (SPA best practices, history API, status codes) .