How to Improve SEO in AngularJS Applications

Search engine optimization is vital for getting your solution in front of the people who need it, and we found out the hard way that AngularJS poses its own set of SEO challenges. Here's how we improved our SEO in AngularJS.

Our AngularJS Application

The Wijmo on-line documentation is an AngularJS single-page application consisting of a page with a Table of Contents (ToC). When ToC links are clicked, AngularJS loads and displays help topics as Partial Views. The Partial Views are static HTML files generated from our source code. The result is a simple and fast website for viewing Wijmo documentation. Our Wijmo documentation, a single-page AngularJS app Our Wijmo documentation, a single-page AngularJS app

Challenges with SEO in AngularJS Applications

We published this application and moved on. We later realized that Google was indexing it, but not the way we wanted it to. We hadn’t considered SEO for our documentation, which was a mistake. Once we realized this was a problem, we began investigating the root issues. There are two main problems we had when hosting content in an AngularJS application:

  • The title and description were not being indexed for each “page” in our documentation
  • Google was not crawling all of the links in our documentation

The good news is that Google DOES render the AngularJS application and indexes the content after the JavaScript has finished rendering! So people were finding our topics through Google, but the results they saw in Google were bad. To see how Google displays a page, you can use the info: command. Here's how Google indexed our FlexGrid Class documentation page: Search results showed the same title for all pages Search results showed the same title for all pages Things to note:

  • The title is “Wijmo 5 Help,” the title of the main page of our documentation. We weren’t updating it during navigation, which meant Google saw every documentation topic was title as Wijmo 5 Help.
  • The description consisted of the first content Google found in the page. It’s relevant to FlexGrid Class documentation, but it isn’t what we wanted to be displayed.

Here’s how we want our FlexGrid Class documentation to be displayed in Google: Google Index With Title Display a reader-friendly, relevant title and description We now have a title specific to the FlexGrid Class topic and a more readable description. Here's how we did it.

Updating Meta Data When Navigating in AngularJS

Solving the issue of how Google displays our documentation topics in results is very simple. We need to update the <title> tag and <meta name="description" content="" /> tag each time a topic gets loaded in by AngularJS’s router. This is a best practice, regardless of whether you want SEO. It’s always good to keep your title updated based on context in your application. It’s also important for accessibility to keep the title updated based on application context. In order to update these tags, we need to create an event handler.

  1. We attached a handler to the routeChangeSuccess event in our Angular application. We use the event handler to attach this even when the application first starts.
  2. Then we attached an additional handler to the $routeChangeSuccess event on the $rootScope. (This event will be fired every time navigation occurs in our application.)
  3. Finally, we used setInterval to check every 200 milliseconds until the navigation is complete.
// handle successful topic loading ($rootScope, $window) {  
$rootScope.$on('$routeChangeSuccess', function () {  
var interval = setInterval(function () {  
if (document.readyState == 'complete') {  
//code that executes when partial view is loaded  

}, 200);  

Now that we have the event handler, we can update the tags. You might want to make this based on data in your $scope. But we have static HTML that contains the information we need. So we will do some DOM querying to get it.

  1. First, we find the first tag inside our main content element.
  2. Then we set the document’s title to the text content of the heading tag.

I also appended “Wijmo 5 Help” to it for some more context.

//find the main heading tag for the help topic  
var heading = document.querySelector('#content h2');  
if (heading !== null) {  
// set page title to topic heading  
document.title = heading.textContent.trim() + ' - Wijmo 5 Help';  

Next, we need to update the meta description tag. This one uses a slightly more complicated DOM query. We use the attribute selector to find the meta description tag—there are many meta tags, so it’s important to update the description meta tag. The content we get for the description is the tricky selector.

  1. First, we find the first paragraph inside the main content element.
  2. Then we use the :not and :empty selectors to make sure the paragraph isn’t empty.
  3. Lastly we set the meta description tag’s content to the text content of the paragraph we found.
//find meta description tag  
var meta = document.querySelector('meta[name=description]');  
//find first paragraph in the help topic that isn't empty  
var content = document.querySelector('#content p:not(:empty)');  
if (meta !== null && content !== null) {  
// set meta description to content of first paragraph in topic  
meta.setAttribute('content', content.textContent.trim());  

That’s it! Now we’re properly updating our title and meta description for each topic in our documentation.

Helping Google Crawl AngularJS Applications

Another issue we had was that some of our links were not being followed by the Google crawler. After some investigation, we found that some links were using an ng-click attribute instead of the standard href attribute on hyperlinks. This was an easy fix for us, since we were routing to a new URL in the ng-click event. We simply needed to change those hyperlinks to have a href attribute set to a navigable path. Once we made that change, Google was able to follow all hyperlinks in our documentation.

Use HTML5 Mode

In order to have more SEO-friendly URLs in our AngularJS application, we enabled HTML mode in our router. It consists of adding a element and calling $locationProvider.html5Mode(true). We also had to make some changes in our server config to map requests to subdirectories to our main page. You can follow other instructions on how to implement SEO friendly URLS.

Generate a Sitemap for your AngularJS Application

Now that we have our application cleaned up, we’re going to make sure Google indexes all of the “pages” in our AngularJS application. In order to do that, we’re going to generate a sitemap for our help topics. A sitemap tells Google about all of the URLs that you want to be indexed, and how they’re structured on your site. This step isn’t required, but it’s recommended. We already have a Table of Contents for our help documentation, so I simply used that to generate a sitemap.

Verify and Submit Using Google Search Console

I use the “Fetch as Google” feature in Google Search Console to see if Google is rendering my Angular application correctly. This won’t give you a ton of information, but it’s helpful to verify that your AngularJS application is being indexed. Once everything looks good, you can submit the application to Google Index. Here’s how to do it:

  1. Enter the root URL for your AngularJS application into the “Fetch as Google” textbox.
  2. Click Fetch & Render. 05_CrawlThisURL Tell Google to crawl your URL
  3. Once rendering is done, click the “Submit to Index” button.
  4. Select “Crawl this URL and its direct links” and click Go.

Your application will be submitted to Google’s Index. Note that it takes some time for the site to be indexed and show results in Google.


It does take some time and it’s a little tedious, but making your AngularJS applications more SEO-friendly is definitely worth doing. We were able to greatly improve the results showing up in Google search using these steps. I hope these are helpful to you as well. Another option we didn’t cover here is rendering from the server. There are some interesting tools that render AngularJS applications into static html pages on the server. I did not test this approach, but it certainly has its merits.

Chris Bannon

Global Product Manager of Wijmo
comments powered by Disqus