By: [email protected]

An exploration into Flutter's SEO performance and potential improvements

Published 2/28/2022, 10:48:23 PM


Flutter SEO - Intro + SEO Renderer

Introduction

Thus far, this blog has been entirely private. I've told some people personally about it, but I haven't posted it anywhere, haven't advertised it, or anything really. It's intended to be primarily for my learning and practice, however, maybe it's time to put it a bit more out there? To that end, I wanted to add some good old-fashioned Search Engine Optimization to this site so people could find and hopefully benefit from it much more easily.

The Problem

This website is built using Flutter which is fairly bad with SEO - a bit weird considering this is a Google framework but separate discussion. This isn't exclusive to Flutter, it's an issue with any JavaScript/SPA based frameworks - see Vue, React, etc. - however because of the way Flutter 'draws' its scenes, it performs even a bit worse at this time. The real truth of this situation is that a 'real' website isn't really what Flutter or those frameworks are made for. SPAs, PWAs, etc. are exactly what they say they are - web APPS - not websites but applications.

Maybe mostly a semantic distinction but I think it plays out once in a while with requirements/features like this. That said, let's see what we can do to improve it even just a little. This will probably be multiple parts as we go step by step improving it and learning.

DanielNazarian.com Setup

So just some brief context - my website/blog is a normal Flutter Web website. It's built off my personal bootstrapper and so contains a lot of my opinions but is overall a pretty basic set up. It uses a Django backend - that is where the blog posts themselves are stored. The blogs are written and generated as HTML and sent to the site where they are rendered for you and I to read. This is a pretty key part since a big part/improvement to the SEO will require indexing the content of said blog posts.

As we'll see, this is probably the most complicated part of the equation and is also pretty unique to my website. That said, there are many, many aspects to SEO compatibility and ways to improve. I think that with Flutter, especially while it's still growing, it's important to have numerous tools and solutions in your toolbelt to help you get some usable solutions and so hopefully by running through my situation(s) we can come up with such effective tools. For example a big part of SEO is simply making your website easy to crawl by Google.

As we've said this is difficult for a SPA or JS based app as Google's crawlers don't work well with that. This is one of the big problems we'll face in general with SEO and try to tackle in this post using a Flutter package.

SEO Renderer

First attempt at this will involve a (the only) package for Flutter that is aimed at improving inflexibility - SEO Renderer.

Pseudo Instructions

Just as a disclaimer, I'm not going to run through a tutorial of how to use the package - their docs will do a better job of that - but I will give a quick overview, some notes on any weirdness and ultimately a review of effectiveness. The gist of this plugin is pretty simple though. First you add the dependency and install as you would any other package.

The first thing is you want to modify the root of your app. The docs will have better instructions on how to do this, but it involves adding a wrapper widget to your root widget as well as a ' navigationObservers' which I will discuss in more detail later. The biggest thing this package does is expose and almost translate your content. By doing so, this package is able to take said content and make it crawl-able by Google or whatever search engine (remember the SPA/JS issue?)

Sounds complicated right? Thankfully no! This package is actually super easy to use, it provides wrappers for different types of content, and it is just on you to actually apply it. For example, you'll want to wrap all your text like so:

TextRenderer(
    child: Text(
        'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
    ),
)

Pretty straightforward. Works with virtually any widget as well so for example I prefer 'SelectableText' over 'Text' for websites, so my widget(s) look like:

TextRenderer(
    text: text, child: SelectableText(
        text,
    ),
);

And that's about it. It's definitely a big refactoring job and requires a good bit of testing but as far as implementation it's fairly straightforward. There are other 'renderers' for other types of content - images and links specifically - so be sure to implement those as well if you're interested in having those be indexed. I'd also recommend switching your browsers' user agent to mimic a Googlebot, so you can see how well it's working (or not) - learn how here. At that point you page should look something like this:

Indexed Home

The red text is what Googlebot would see - not your users - so this is ideal and means everything's working as expected!

Navigation Observers

The 'navigationObservers' is where I had a weird issue, so I thought I'd quickly run through that. I use an external package for navigation 2.0 in Flutter ( see Routemaster) and so I was not able to modify my 'navigationObservers' as easily. Even more, Routemaster uses its own class for such observers - aptly named "RoutemasterObserver". To fix this, I made my own observer class that used the functionality I needed in both packages. My class looks a bit like this:

class SeoObserver extends RoutemasterObserver {
    @override
    void didPop(Route< dynamic > route, Route< dynamic >? previousRoute) {
        seoRouteObserver.didPop(route, previousRoute);
    }
}

By inheriting from "RoutemasterObserver" we are able to use this with Routemaster, however in the actual functions we rely on "seoRouteObserver" from the seo_renderer package to ensure we are using that functionality. Then, simply feed this class to Routemaster as your observer:

final RoutemasterDelegate routemaster = RoutemasterDelegate(
    routesBuilder: (BuildContext context) => routeMap, observers: < RoutemasterObserver >[SeoObserver()],
);

And you should be good to go. Please note: this solution only works if you're using Routemaster but other navigation frameworks/solutions will probably require similar. This does open a bit of a Pandora's box of potential issues you could run into since you don't know exactly which functionality you need and are missing from either side of this equation.

Performance

Well that's all fun and great but how does it actually perform? SEO is a bit of a black box outside of Google and even more kind of endless struggle, there's never a good stopping point. Hence, while I usually stress the importance of benchmarks, I would say they're even more necessary with this to help see how much progress we're actually making - or if we're just wasting our time.

Scores

So, first, an easily quantifiable benchmark. There are a million ways to rate your SEO, all very subjective, I've found https://freetools.seobility.net to be very solid, fast and FREE. Before doing any work, I ran the test to give us a nice 'control' group:

SEO Score 1

I then updated the code, pushed it live and waited a few days for Google to re-crawl and all that fun stuff. Upon waiting, I reran the test and got:

SEO Score 1

nice. The astute among you may in fact notice, these are the same photo! Because the results were identical! So I didn't even bother uploading the second screenshot! Not a great outcome but good to know!

Issues

So the scores don't mean a ton to me honestly, if this helps at all that's a win in my book. However, after a few days of letting this run live I started noticing some weird issues. I set up my Flutter apps to send me emails when they crash, and I quickly started being spammed with the standard illegible Flutter source map emails like so:

Flutter Error

These would come 25-100 at a time. Even more, it was due to actual issues in the site - namely some issues with navigation but this probably has to do with the fact that I am using an external library for navigation - see and again recommend Routemaster.

Search Performance

All the above issues and performance (or lack of) aside, again I pushed this package to my live site for a few days to see if it at least helped the ultimate SEO problems. This test is FAR from scientific but every few days I would Google search "Daniel Nazarian blog NextCloud" to see if it would bring up my post - not many Daniel Nazarians are writing about NextCloud it seems. Lo and behold, even after a week of waiting our results were sad as ever:

Google Search Results

I'd like to say one more time - this test is in particular far, far from scientific. As said earlier it was struggling to index any of the post content itself - it was able to get some titles though:

Indexed Posts

All said - the How, when, why, etc. Google indexes is one of the mysteries of life at this point but my thought is simply if after a week this package didn't help this super specific search, I'll probably need a 'more radical' solution.

Conclusion

So overall, this package works well but definitely has some issues. It definitely covers the majority of Flutter websites, however, more complex ones clearly need to look elsewhere. We will continue investigating this topic to see just how much we can improve the SEO situation for Flutter apps and maybe other SPAs. There are a few other tricks and methods I think we can try to get this performing better. For the time being I did remove this package from my site to test other options more thoroughly - i.e., ones that could help index the blog posts themselves.

Once again as well, while I love me some Flutter, unless you're already stuck with it, I'd recommend another route if SEO is at all important. While as we've discussed and seen there are ways around these issues and ways to mitigate them, the reality is at the time there are a lot of obstacles towards 'true' SEO.

That said, Flutter is still young and considering it's Google's baby I think it's safe to say there will be better SEO support eventually - check this GitHub issue for progress and obstacles. That said, in the meantime, if SEO is a priority for your website or project I would recommend staying away from Flutter or similar frameworks. I would opt instead for one that supports server-side rendering (SSR) like NextJS.


Comments

None available :/

Must be logged in to comment


Tags

Flutter