September 10, 2015
[SEO] AngularJS remove Hashbang from URL’s – seosafe
By default AngularJS projects use the hashbang syntax for urls to handle navigation without forcing the client to reload the whole application on every state change. Since the (HTML5) History API is available in all modern browsers the usage of the hashbang is not really required anymore. Furthermore urls look way cleaner without the hashbang. The removal is pretty simple, but even slight errors could either cause legacy browsers to have problems with your site or even worse – google may remove your rankings in the search engine results since your single page application is not crawlable anymore.
This blog post will provide you with the proper way to rearrange your urls in order to remove the hashbang from your urls. We’ll assume that you’re running the Angular UI Router and have access to the server component which is necessary in order to redirect all requests to your single page application entry point. If you are rearranging your url structure, consider implementing https since it will affect your ranking and you are going to touch your urls anyway.
1. Set-up your angularjs application for seo friendly urls
1.1 ui-router-conifg
The configuration will be set in your modules config part. Just add the following line to enable html5 mode.
1 2 3 4 |
module.config(function ($locationProvider) { $locationProvider.html5Mode(true) $locationProvider.hashPrefix('!'); }); |
Apart from some small trivia your application should now be able to run in html5 mode – urls should look like domain.tld/route/route/
We need to add the hashPrefix in order to redirect old urls to the new schema, e.g. domain.tld/#!/route to domain.tld/route
Things that wont work right now:
- deep linking into your application
- reload on pages other than the start view
- support for some legacy and mobile browsers
- redirect old links for users and for google
1.2 set base url
Now we have to set the base url in your index.html file. This will enable the loading of resources inside of your application. Otherwise you will experience an error if you are in the state /foo/bar of your application and call a directive that renders the following image tag:
1 |
<img src="assets/images/imageFromDirektive.png" alt="foo"> |
and your files look like this:
1 2 3 4 |
./assets/ ./assets/images/ ./index.html ./app.js |
your browser will try to load the file with the wrong path “foo/bar/assets/images/imageFromDirektive.png”. The base path tag will tell the browser not to use the current file path but to start on the root level of your domain which will result in “assets/images/imageFromDirektive.png”
Since Google doesn’t which url schema should be preferred it is absolutely necessary to set canonical tags. The given url will be indexed while other urls linking to the same content wont appear in googles search index. since
1.3 directive for canonical-tags
Since not all browsers are capable of handling the HTML5 history API it is absolutely necessary to keep the urls with hashbang accessible for users with legacy or mobile browsers. Google doesn’t know which url structure should be preferred. That’s why we need to provide some information with canonical-tags. This can be achieved pretty easily. It gets a little bit more complicated when you have url parameters but this directive will help you to set up your canonical-tags correctly. w11k.angular-seo-header.
Furthermore you can use the directive to output url parameters directly into your html title-tag, meta description or keywords. Since you can also enter a function it is no problem to map url parameter to readable text or other informations.
install w11k.angular-seo-header using bower
1 |
bower install --save w11k.angular-seo-header |
then add it to your module
1 |
angular.module('myModule', ['w11k.angular-seo-header',]); |
finally pass the head object to your view data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var module = angular.module('myModule', ['ui.router', 'w11k.angular-seo-header']); module.config(function ($stateProvider) { $stateProvider .state('home', { url: '/home', data: { head: { title: 'Page title for this View', keywords: ["Array", "of", 'Keywords'], description: "your meta description", robots: "index,follow", canonical: 'https://www.mySite.tld/home', } }, }); }); |
if you have any parameters set you can access them for each tag with an extend function. e.g. for canonical and title tag with 1 parameter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
module.config(function($stateProvider) { $stateProvider .state('route', { url: '/route/:param1', data: { head: { title: 'My View Page-Title', keywords: ['keyword 1', 'keyword 2'], description: 'Meta Description for View', robots: 'index,follow', canonical: 'https://www.domain.tld/#!/route/', canonicalExtend: function (canonicalStr, toParams) { return canonicalStr+toParams.param1; }, titleExtend: function(titleStr, toParams){ return titleStr + capitalizeFirstLetter(toParams.param1); } } }, |
2. server side configuration
Since your app can’t handle deep-linking right now we need to adjust the server config to direct all incoming requests directly to your index.html.
for apache:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<VirtualHost *:80> ServerName my-app DocumentRoot /path/to/app <Directory /path/to/app> RewriteEngine on # Don't rewrite files or directories RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] # Rewrite everything else to index.html to allow html5 state links RewriteRule ^ index.html [L] </Directory> </VirtualHost> |
for others servers you find a sample config here: ui-router-wiki
3. why canonical and why you really should NOT use 301
It’d be possible to redirect all hashbang links to the new html5 structure, but what about our old friend internet explorer 9? Angulars html5mode doesnt work with it and we need to keep the hashbang structure alive
You can see running example at https://www.thecodecampus.de.
[…] use the HTML5 History API Which is very easy with ui-router. You’ll find further information in the article about migrating existing projects from hashbang to regular urls. […]
Very useful tutorial. One of the best i’ve seen
Thanks a lot.
To page reload issue in angular Js that too very old version I took 3 days to work. But this site code chunks helps me a lot. A very big thanks to you.