SEO (Search Engine Optimization) is one of those topics that feel uncomfortably big if you're just starting out. Even more so if you have built a Single Page Application (SPA) and heard that SPAs could be problematic for SEO and visibility on search engines.
Is your Vue.js SPA doomed to never rank well? Scary stuff. We're going to recap on what is known about SEO for SPAs and JavaScript, and list a lot of handy resources full with info by people who know best (which is often Google themselves) and tools you can use.
Search engine optimization is not the ever-changing voodoo it appears to be.
It's a set of best practices that help Google and other search engines make sense of your site, with the goal of ranking well in search results. Those basics certainly don't change with every Google update.
Search engines get better and better at discovering if your content is any good and if people like it or not. They analyse factors like click-through rates on their search results, session time after clicking on a search result, how often that content is shared on social and many other signals.
SEO hacks and tricks won't get you anywhere long-term. Ignore the temptation to use tactics that promise immediate success, as you'll only risk getting penalized (= ranked lower).
Content will always have the most impact on your rankings. People engaging with your content is a good sign for search engines. Quality content is also helpful for link building: Having trustworthy sites link to you is a strong ranking factor. Trustworthy sites prefer to link to good content. Go figure!
Then there are some technical best practices that you need to get right:
Summarized: Create good content that people engage with, make sure it's machine-readable and accessible. The problem with SPAs lies mainly in the machine-readable part.
To help you with the basics, you can look into the following resources:
If you want to read more about the topic of SEO in general, we can only recommend reading Understanding SEO by Franz Enzenhofer, which is probably the most no-bullshit guide you'll find about SEO.
Single Page Applications (SPAs) send all of the site's code within one page load and dynamically change and asynchronously load content depending on how the user navigates. Per default, it relies on client-side rendering and only provides an empty app shell or container at first.
Browsing an SPA can feel fast and snappy. They're fun to build, too.
But remember: Content is really important to search engines, so it doesn't sound like the best idea to not have any content on your page and only fetch it later. Right?! It makes it harder for your pages to be machine-readable.
When a crawler visits your SPA for the first time, it will usually only index what it sees without running JavaScript.
That doesn't mean Google and some other search engines do not execute JavaScript. They do that since about 2015. Google does index content generated by Vue. But crawlers usually only do so on their "second wave of indexing": When they crawl your site initially, they want to index it as efficiently as possible (there are so many new pages to index every day!). They will usually only use more time and resources to execute JavaScript when they come around to your page a second time.
This is very much an oversimplification of what really happens, but it helps understand the problem. Crawlers have a certain resource budget for your page, called a "crawl budget" that is calculated by how important it thinks your page is, and also f.ex. your page load time. As executing your JS uses up more resources, there may not be enough budget left to crawl all of your content. This could results in visibility problems for some of your content.
Besides that, Google is of course not the only search engine out there, and many others don't crawl client-side rendered content as well.
Using client-side rendering makes your site being indexed more susceptible to crawling errors compared to markup that is already rendered. If there's a JavaScript hiccup, the crawlers won't see anything. Error-free rendering can't be guaranteed, especially as f.ex. Google's crawlers don't all run on the same version of Chrome.
But: Once indexed correctly, your pages should not have any disadvantages for ranking.
Your takeaway should be this: Yes, search engines render JavaScript, but don't rely on the crawling of asynchronous content too much, especially if you..
If you want to dig deeper into how search engines index SPAs, check out these resources:
Every page should have a separate URL. If you want a piece of content rank on search, it does need a "home". It's just not that straightforward with SPAs. Routing is important to get right, and a clean URL architecture is a must-have.
With 'history' mode (as opposed to the default 'hash' mode) of Vue Router, you can create SEO-friendly URLs instead of #hash fragments added to your base URL. This mode leverages the History API of the Window DOM object to manage the user's browsing history without needing a page reload.
Check the official guide for History mode of Vue Router to see how to configure it right.
Critical content should better be included in the source markup to avoid indexing problems. To achieve that while still using an SPA architecture, you can use server-side rendering or prerendering.
With server-side rendering for SPAs, the rendering is done directly on a web server. (It's often done using Node.js, as the official vue-server-renderer package uses it, but it could be done with f.ex. PHP as well.) The generated HTML views are then served to the client. Each route will be a separate HTML file.
By using SSR, crawlers don't need to execute your JS any more and have everything they need upfront.
As we need a server for this, a server-rendered Vue app has to be a "universal" or "isomorphic" app: This means it has to run on both the server and client, making it a bit more complex to build and deploy. But don't worry, there are a lot of resources that can help you:
SSR is not something that we have invented to make Vue.js apps SEO friendly, of course. Traditional ("coupled") CMS have been doing this forever: Upon request, they pull content out of their databases and serve a rendered HTML to the client. As rendering on demand tends to slow things down a bit, we now have nice solutions like headless CMS that deliver static sites. (Read more about headless and JAMstack with Vue!) So in fact, we're just using proven concepts to complement our modern tooling.
There are services and plugins that offer to pre-render your SPA (or just specific routes). This is useful if you want to make parts of your SPA easier to index and is perfect for projects where true SSR would be overkill.
Prerendering works by booting up a headless browser that generates a rendered version of your SPA at build time and delivering it to crawlers.
You can achieve this f.ex. with prerender.io, which works with Vue.js and every other framework. Besides their paid service, prerender.io also offers an open-source version 6481. If you're using webpack, you can also use the prerender-spa-plugin 7324 that offers a simple Vue.js example as well as an example with Vue Router.
It's usually not recommended for large SPAs or very dynamic page content. Be sure to not serve too much different content to crawlers and users: Search engines could interpret that as deception, as you could pretend your page is about x, while sneakily serving y. This is called "cloaking" and they don't like it because "clever" SEO people used it to serve pornographic content cloaked as non-pornographic content. So much for hacky SEO tactics! 🙄
Check for all the SEO basics we already listed in this article: Engaging content, performance, mobile-friendliness, accessibility, security, rich metadata.
If you feel concerned about getting this right, and haven't yet built the SPA you want to optimize for search: Maybe an SPA is not the right solution, after all?
Disclaimer: What follows is a personal approach, and maybe it's an unpopular opinion. I usually only recommend SPAs for (parts of) apps where ranking on search is not business-critical.
I officially feel like an old man saying that, so go on and make that joke about the guy using PHP 🙃 But: Don't create an SPA just because you feel that it's the "modern approach to web development". Choose it intentionally for all the advantages while knowing about the SEO caveats. And optimize the hell out of it.
So we saw that you will have to work on SEO more for an SPA, and you will kind of need to know what you're doing. It is certainly not impossible to have an SPA rank well, but you have to decide if this approach really fits your project requirements.
By all means, this does not mean Vue.js and SEO don't go together. First, SPAs sure are not the only Vue.js use case. Second, Googlebot and other search engines are able to render JavaScript. The remaining issues with this will probably solve themselves with time. Third, prerendering and SSR work great once set up correctly. So if you want to build your blog as an SPA for the fun of it, go ahead!
Start with SEO-friendly URLs and prerendering or SSR, and keep on improving on the basics.
If you are an SPA SEO wiz, share your experiences with us on Twitter @madewithvuejs - we're curious! 🤓