Solutions to search engine optimisation (SEO) for Blazor WebAssembly

How I broke Blazor WebAssembly to fix SEO

I’ve been working to develop a web application using Blazor WebAssembly, the framework enabled me to build high speed apps within my site using a language I’m familiar with (C#), and libraries essential to my apps function (SkiaSharp).

However, when I came time to publish my app, I discovered that there were several major issues which would impact my site’s SEO, preventing it from being shown to users.

Image of SEO score
Image of SEO score

Largest Contentful pain (LCP)

“The Largest Contentful Paint (LCP) metric reports the render time of the largest image or text block visible within the viewport, relative to when the page first started loading.” - Source

My Blazor app with runtime relinking and Brotil compression enabled had an approximate size of 3mb. Using googles page speed insights app (https://pagespeed.web.dev/) the LCP measurement for mobile or desktop experiences were both in excess of 6 seconds (Considered Poor by google). This was because the app needed to be downloaded and decompressed before

History of CLS issues
History of CLS issues

Cumulative Layout Shift (CLS)

“CLS is a measure of the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifespan of a page.” Source

Google measures CLS when validating SEO because content which shifts around negatively impacts user experience. For instance, if the user is trying to read text and they lose their place or click a button and a shift causes them to click the wrong one.

During the initial load of a Blazor WebAssembly app the CLS is high as additional DOM elements are appended dynamically. Each time an appended element makes changes to the layout the CLS value increases.

Meta data & Content

Meta data tags are important for letting google and other websites know how to display links to your website. https://developers.google.com/search/docs/crawling-indexing/special-tags

Additionally Google uses the content found within the page to rank its’ the relevance to a user’s search term. Meta data is normally set in the Head element of a webpage and content is crawled from what is found within the pages Body element. However, because Blazor app run as single page applications and generate content dynamically, Google’s web crawlers can struggle to see content which is not explicitly set in the sites main index.html.

How I Solved These Issues

I primarily solved these issues by operating Blazor as a multi-page application and delaying Blazor initiation until an initial page containing core information and images had finished loading.

Operating as a Multipage App – Because of this I was able to move static information such as meta data and static content (text and images) from the app and onto a html page for each URL. This ensured that such information would be picked up by web crawlers.

To make this work you will need to set any links to force reload the page (bypass Blazor’s router), by setting the target attribute to “_TOP” or use “NavigationManager” within the Router component to force a reload if when navigating to a new URL.

Delaying initiation – This meant that the CLS caused when Blazor adds elements did not take effect during the initial page load. I implemented this by giving the user a “Star App” button to press. When pressed it starts up Blazor and stores a variable in local storage which tells the webpage not to wait for input the next time.

However, this just delays the CLS until after the user clicks the button, so to fix that I added placeholder content inside the app root element on the html page. The placeholder mimics the final content on the page so that the page doesn’t shift around Blazor overwrites it.

Image of the placeholder page
Image of the placeholder page
Image of the final page
Image of the final page

Downsides

  • You will need to build html pages for each URL.
  • Internal navigation takes longer than with single page applications.
  • The total time until the app is first usable is increased, however this is not picked up by google.
  • Progressive web applications (PWA) will no longer be supported.

Disclosure

I am not an expert at Blazor or Web development, these are solutions that I came up to solve problems my website had which effected SEO. These solutions may not apply to your specific use case or may become obsolete as Blazor WebAssembly is developed.

Please get in contact if you have an issue with any of my statements, I have a limited understanding of Blazor’s inner workings and would hate to spread fallacy.