Compilation issues with Sitecore Commerce 9 Business Tools SDK, a.k.a Sitecore BizFx SDK

Like Sitecore Commerce 9 Engine SDK, which is used for creating custom plugins, Sitecore Commerce 9 Installation package also comes with Sitecore Commerce Business Tools SDK. This SDK is used to modify the Business Tools. For example, if you want to add a new commerce entity and you want to manage that from the Business Tools, you have to use BizFx SDK.

Now, there are multiple issues to make BizFx SDK working in Sitecore Commerce 9 update-1. Here is the list.

  • You may not have @speak and @sitecore registry in your .npmrc file. Run following commands to add them in the .npmrc file

    npm config set @speak:registry=

    npm config set @sitecore:registry=


  • “@sitecore/bizfx”: “^1.1.9” is missing from package.json. Add that.
  • “@speak/icon-fonts”: “~1.0.2” is missing from package.json. Add that.
  • “@speak/ng-bcl”: “~0.8.0” and “@speak/styling”: “0.9.0-r00078” are missing from Sitecore npm repository:
    For some reason Sitecore has not included these version of Speak npm packages in npm repository. They have included the packages with the Sitecore Commerce 9 installation package in the root directory. You need to install these packages from the file system. Modify “@speak/ng-bcl”: “~0.8.0” and “@speak/styling”: “0.9.0-r00078” as follows in the package.json.

    “@speak/ng-bcl”: “file:../speak-ng-bcl-0.8.0.tgz”,
    “@speak/styling”: “file:../speak-styling-0.9.0-r00078.tgz”,

Once above changes are done, save package.json and run the command ‘npm install‘. This will install all the required packages to the solution. If the BizFx SDK compiles without any error, run the command ‘ng serve‘. This will host the Business Tools in webpack dev server. If you go to http://localhost:4200, business tools will be launched.

Webpack will throw port not available error if SitecoreBizFx site that is installed with Sitecore Commerce 9 is running in IIS. Stop this site and run the command ‘ng serve‘ again.


Posted in Sitecore Commerce | Tagged , | Leave a comment

Yet another Sitecore Commerce 9 installation blog post

Update: Issues discussed in this article are on;y applicable to Initial Release of Sitecore Commerce 9. None of these issues occurred in Sitecore Commerce 9 Update 1.

If you are here and reading this blog, you probably have some problem installing Sitecore Experience Commerce 9 in your computer and you have problem because your machine configuration is not exactly what Sitecore Commerce 9 installation script expect it to be. You may have one or many of the following differences.

  • You have more than one instance of SQL Server installed in your machine and none of them are on localhost.
  • You have more than one disk drive and you want to install commerce websites in folder that’s not under C:\inetpub\wwwroot.
  • You have Sitecore Commerce 8.2.1 installed in your machine previously.

In a perfect world, we may have a clean machine with SQL Server 2016 SP1 installed on default localhost and have one C drive with default website folder location. In that case, I wouldn’t be writing this blog :). But, the reality is, in most cases we are not that lucky and the Sitecore Commerce 9 installation document is not that helpful in that situation. In my case, all of the above mentioned points are true. So, what issues I have faced and how I got through them with the help of good folks from Sitecore Community?

        1. Sitecore Commerce 9 installation guide has a section for ‘Host environment requirements’. There are list of softwares here, but most of them will be there in your machine when you installed Sitecore 9 update-1. What you need to install are  following
          • Visual Studio 2017
          • .NET Core 2.0.0 Visual Studio 2017 Tooling
          • .NET Core Windows Server Hosting 2.0.0 (if you have x64 machine, use command line installation to opt out x86 .Net Runtime, DotNetCore.2.0.5-WindowsHosting.exe OPT_NO_X86=1)
        2. In most cases you will be using an administrator account for installation and run the script from Powershell Console in administrator mode. Make sure your Windows logged in account is in SQL Server ‘sysadmin’ role.
        3. If you want to install Sitecore Commerce 9 in location other than C:\inetpub\wwwroot, you should be able to change the Drive, but changing the folder name will fail the installation with this error for the package installation Sitecore Commerce Connect Core
          One or more exceptions occurred while processing the subscribers to the ‘item:saved’ event.
          At this point, if you launch Sitecore and open the indexing manager, you will see all indexes are gone. There is not point of return now, you have to re-install everything from scratch again, starting from XP9.
          If you want to change the Drive you have to make changes in the following files. Replace the environment(‘SystemDrive’) with the drive (e.g. ‘D:’).

          Sitecore.Commerce.2018.01-2.0.254\SIF.Sitecore.Commerce.1.0.1748\Configuration\Commerce\CEConnect\InitializeCommerce.json (4 hits)
          Line 32:     "CommerceOpsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceOps')))]",
          Line 33:     "CommerceShopsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceShops')))]",
          Line 34:     "CommerceAuthoringPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceAuthoring')))]",
          Line 35:     "CommerceMinionsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceMinions')))]"
          Sitecore.Commerce.2018.01-2.0.254\SIF.Sitecore.Commerce.1.0.1748\Configuration\Commerce\CommerceEngine\CommerceEngine.Deploy.json (4 hits)
          Line 39:     "CommerceOpsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceOps')))]",
          Line 40:     "CommerceShopsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceShops')))]",
          Line 41:     "CommerceAuthoringPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceAuthoring')))]",
          Line 42:     "CommerceMinionsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceMinions')))]",
          Sitecore.Commerce.2018.01-2.0.254\SIF.Sitecore.Commerce.1.0.1748\Configuration\Commerce\CommerceEngine\CommerceEngine.Initialize.json (4 hits)
          Line 38:     "CommerceOpsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceOps')))]",
          Line 39:     "CommerceShopsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceShops')))]",
          Line 40:     "CommerceAuthoringPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceAuthoring')))]",
          Line 41:     "CommerceMinionsPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', variable('CommerceMinions')))]",
          Sitecore.Commerce.2018.01-2.0.254\SIF.Sitecore.Commerce.1.0.1748\Configuration\Commerce\SitecoreBizFx\SitecoreBizFx.json (1 hit)
          Line 33: 		"SitecoreBizFxPhysicalPath": "[concat(environment('SystemDrive'), '\\inetpub\\wwwroot\\SitecoreBizFx')]",
          D:\Deploy\Sitecore.Commerce.2018.01-2.0.254\SIF.Sitecore.Commerce.1.0.1748\Configuration\Commerce\SitecoreIdentityServer\SitecoreIdentityServer.json (1 hit)
          Line 41:     "SitecoreIdentityServerPhysicalPath": "[concat(environment('SystemDrive'), concat('\\inetpub\\wwwroot\\', parameter('SitecoreIdentityServerName')))]",
        4. If your SQL Server instance is not a default instance on localhost, the installation will fail with following error
          Get Token From Sitecore.IdentityServer
          Install-SitecoreConfiguration : The remote server returned an error: (500) Internal Server Error.

          If this is the case, you need to change the connection string in the json files mentioned in Naveed’s blog post. You might get away with installation by just making the change in \SitecoreIdentityServer\wwwroot\appsettings.json, but it is better to take care of them now than later. Sitecore uses trusted authentication, so don’t change the connection string to use SQL account. Just change ‘localhost’ with your SQL Server instance (machine-name\\instance-name). After making the correction, you can comment out all the tasks before InitializeCommerceEngine in Master_SingleServer.json and run the installation script again.

        5. If you are seeing the following error after running the installation, you might be using one ‘\’ instead of two ‘\\’ in the connection string, like I did and spent hours to find out what’s going on.HTTP Error 502.5 – Process Failure

          Thanks to Kautilya Prasad for helping me with this and actually recreating the issue in his machine.
          This error is little different from wrong connection string. This is a parsing issue in the json config and installation script doesn’t handle the error gracefully. As the effect of that, I was seeing the following error in event log and thought, the issue is something to do with state of .Net Core in my machine. It was bit confusing. So, if you see this error in event log, most probably the issue is related to unhandled error than anything to do with .Net Core installation .

          Application 'MACHINE/WEBROOT/APPHOST/SITECOREIDENTITYSERVER' with physical root 'C:\inetpub\wwwroot\SitecoreIdentityServer\' failed to start process with commandline 'C:\inetpub\wwwroot\SitecoreIdentityServer\Sitecore.IdentityServer.exe ', ErrorCode = '0x80004005 : 0.
        6. If you had installed Sitecore Commerce before in your machine and the account CSFndRuntimeUser existed before the installation, it might have a different password than the one used by the installation script to create the SitecoreIdentityServer website. In this case you might see the following error because the App Pool for SitecoreIdentityServer will be stopped for incorrect password.

          Service Unavailable

          HTTP Error 503. The service is unavailable.

        7. If you are installing the Sitecore Commerce 9 in C:\inetpub\wwwroot folder, script might fail to grant permission to CSFndRuntimeUser account to the folder. If that happens, you can resolve the issue by manually granting permission and re-run the script again.
        8. If everything goes well with installation and the Storefront is failing with Sitecore item not found, publishing the site will probably fix the issue.
        9. Finally, if you are not lucky, you might have to remove the Sitecore 9 and Sitecore Commerce 9 once or more. Get the removal scripts from Sitecore SIF-less blog and Sitecore Commerce 9 SIFLess Uninstall and configure them as per your need.
          You may use my script for removing XP9, but it doesn’t use SIF.

Good luck!

Posted in Commercce, Sitecore Commerce | Tagged , , , | Leave a comment

A Powershell script for removing Sitecore 9 instance from local machine

Sitecore 9 installation process is quite different than previous version. The new installation process uses, Sitecore Installation Framework (SIF). You can find installation documents in Sitecore 9 release page. The earlier version of Sitecore installation was easy and it was not hard to remove a Sitecore instance from the computer. If you had used SIM, it was even easier, just clicking a button would do it.

After I installed my first Sitecore 9 instance, I realized that, it installed the websites in C:\inetpub\wwwroot and created all the databases in the C drive. My C drive is smaller SSD drive and I don’t install Sitecore instances in it. It is reserved for only OS. I thought, it will be useful, if I create a script to remove the instance and share it with others. Here is the script.

There seems to have some issues with gist rendering in the blog. If the code is not displayed in the blog, this link will directly take you to Github gist.

Final Thoughts: SIF is extensible and it is probably possible to extend it to add the instance removal functionality. I will look into that as time permits. Feel free to change the script for your use. Make sure you run it carefully. Once the instance is deleted, nothing can be recovered.

Posted in Sitecore | Tagged , | 2 Comments

Sitecore Commerce 9 is Coming Soon

What a great Symposium it was in Las Vegas. So many familiar faces and so much we have learned from the Symposium and the MVP Summit. My focus in last couple months was on Sitecore Commerce and I tried to learn as much as possible from this event about Sitecore Commerce. It’s time to share some of those information with the community. I am allowed to share only unrestricted information but, don’t be disappointed, Sitecore Commerce 9 will be released soon and you should be able to dive into it and explore more. If you are a Sitecore MVP, you will be able to play with a Tech Preview sooner than that. This blog is to give you some idea of what is coming.

RIP Commerce Server: No more Commerce Server!! I think, every one is happy that, we don’t have to deal with Legacy System anymore. This should make the installation and maintenance of the system so much easier. Look at the following Sitecore 8.2.1 architecture diagram. Aren’t you happy to see all the red boxes are gone?

Sitecore Commerce Architecture

Data Migration Tool: As soon the Legacy System is gone, question will be raised about upgrading the old system. How can we move the Catalogs, Profiles, Orders and Inventory data from Commerce Server to Sitecore Commerce 9? Sitecore is working on a migration tool that will help us to migrate data from old system to Sitecore Commerce 9. As mentioned, we should be able to map fields and migrate data easily from Commerce Server to Sitecore Commerce 9.

New Business Management User Experience: Sitecore Commerce Business Tools like, Merchandising Manager, Pricing & Promotion Manager and Customer & Order Manager are not part of Sitecore Dashboard anymore. A new Business User Experience Manager is coming (looks similar to one in Sitecore 8.2.1). The new UI is built using SPEAK 3 component, which is using Angular 4 as the building block. Original SPEAK based UI is gone. The new Business Management Tools are task centric, data driven and extensible. So, if we need to add a new menu or tab in the Business Management Tool, we can write our own plugin and expose the data in the Business User Experience Manager.

Federated Authentication: Sitecore Commerce uses Sitecore’s Authentication model for authenticating and authorizing users. With Sitecore 9, Federated Authentication is now a choice for Sitecore Commerce application. This opens up the possibilities of connecting different third party systems to Sitecore Commerce Securely.

Catalogs and Inventory: The terminology Sitecore uses for product is Sellable Item. The reason for this is, a product may not be a physical product but anything that customer can sell. For example, customer can sell service. In Sitecore 9, Sellable Items are independent of Catalog and they can be used in more than one Catalog. The Categories are part of a Catalog and Sellable Items can belong to more than one Categories. The Inventory is now part of the Sellable Item and inventories belongs a Inventory Set. The Inventory Set is useful to represent multiple warehouses based region or site/sub-site or differentiate inventory based on brick & mortar or online. Following diagram shows the relationship.


The schema for Sellable item is based on Product Schema. This makes it possible to map the Sellable Item in JSON-LD directly for google product search markup. The Variant Sellable Items are child of original Sellable Item. The schema is basically same and variant properties are overriden properties.

SXA Storefront: Sitecore will be releasing a new Storefront based on SXA. This will include many commerce specific components with capabilities of creating multi tenant ecommerce website. The solution is based on Helix architecture.

ASP.NET  Core 2.0: Sitecore Commerce 9 is built on latest ASP.NET Core 2.0 and the architecture is based on Lightweight Micro Service architecture. This opens up lots of possibility in future to use services in cross platform and take advantages of distributed architecture.

Azure PaaS Support: Since the Commerce Server is not in picture any more, Sitecore Commerce can be deployed in Azure with very little effort. It can take advantage to standard Azure tooling, High Availability, Disaster Recovery etc.

I cannot wait to try Sitecore Commerce 9. There are so much to explore. As I learn more, I will share with the community.


Posted in Commercce | Tagged , | 1 Comment

How to debug Sitecore Commerce OData APIs in Fiddler

Sitecore Commerce  APIs are based on OData. When Storefront makes call to Sitecore Commerce Engine, it uses OData clients, which are Commerce Services Proxy generated using T4 templates. If you download Sitecore Commerce SDK, you will find the several Postman Collections, which are json files you can load in Postman tool and fire the OData APIs. Postman is very useful to debug OData APIs but, I find Fiddler is useful for this purpose too. What I find useful in fiddler is, when I am debugging code in Visual Studio or just using the website (storefront), if I would like to see the OData APIs in use, I can see that in Fiddler. Once, I capture the API in Fiddler, I can replay it in Fiddler Composure as many time as I want.

In this blog, I will discuss, how we can setup Sitecore Commerce, so that, we can capture the OData APIs in Fiddler. We will be using Sitecore Storefront, so setup starts from there. The OData API calls are made from ASP.NET server side code. How can we setup the Storefront application, so that, this API calls from the server side code can go through Fiddler. Here is how.

Open up the web.config file for Storefront and add the following in that file


You can find more information in telerik website here

Once that change is made OData calls will be routed through Fiddler, but still it cannot be seen in Fiddler because, base URL for the Commerce Engine site is setup as http://localhost:5000 per Sitecore installation instruction. Fiddler doesn’t capture traffic on the localhost. So, we have to use a different base URL.

First setup a different binding for Commerce Engine site. Open up the site in Internet Information Manager and changed the binding as follows and removed the binding with empty Host Name.


To access the site on that binding you need to add that in the host file. Open up the host file and add commeceauthoring as a new entry. Now, if you go to browser and access http://commerceauthoring:5000/api/$metadata you will see the OData metadata information for Commerce Engine.

Next open up Sitecore.Commerce.Engine.config and Z.Sitecore.Commerce.UX.Shared.config in Storefront and replace localhost with commeceauthoring. Setup is ready now to capture the Sitecore Commerce OData APIs in Fiddler.

Start fiddler and make sure you are capturing traffic from all processes, not only from the browser. Now, if you open the storefront site in browser, traffic will be captured as shown below. This was captured when I went to product detail page.


If you select the request, you can see the request and response on the right.



You can right click on the captured request and go to Replay -> Reissue from Composure to debug the request in Fiddler Composure. You can change request parameters and play with the API.


That’s it. Happy debugging!

Update: When you are done with the debugging make sure to remove the configuration from the web.config. If that configuration is there and you are not running Fiddler while using the site, you will see errors in the application because, there is no way to route the request to Fiddler.


Posted in Sitecore Commerce | Tagged , , | Leave a comment

Sitecore Commerce Pricing Feature

Pricing is one of most important and complex features in any eCommerce product. New Sitecore Commerce has introduced a much improved pricing engine than what used to be in Commerce Server. In this article, I will explain Sitecore Commerce pricing features and show you how to work with them in Sitecore Commerce Administration Console. Let’s get familiar with the pricing terms used in Sitecore Commerce and see how to configure them.

Price Book: A Price Book in Sitecore Commerce is the first level construct of organizing the pricing. Say, you want to keep all the pricing for products for a country or a web store in one place, you can create a Price Book for that. A Price Book can be associated with multiple catalogs. If you want to remove the pricing for all products in a catalog, you can just disassociate the catalog from the Price Book.
To create a Price Book, go to the Sitecore Dashboard and click on the Pricing and Promotion button.
This will open up the Price Book list page where a new Price Book can be created by clicking on the ‘Add’ link on the right. I created a Price Book called ‘US Pricing’.
Next, open up the Price Book and associate the Price Book to the Catalogs. I associated it to Habitat_Master catalog.

Price Card: A Price Card is a construct to organize different kinds of pricing for products. Price Card is selected in the product and price gets calculated based on the configuration in the Price Card. Price Card include tags and break pricing to define the price at the currency level. To create a Price Card click on the ‘Add’ link in the Price Card section of the Price Book. I created Price Card called ‘Quarterly Sale’ shown below. I will use this Price Card for defining the product pricing for quarterly sales.

Snapshot: Pricing in Price Card is defined using a Snapshot. A Snapshot has a starting date. That means we can plan and create pricing that will start at some future date. Price Card use the Snapshot that is currently selected and apply the pricing from that Snapshot. Below is a Snapshot I added for the first quarter of 2017.

Tags: Price from Price Card can be applied to particular product or it can be applied to range of products based on tags. In above screenshot you can see I added a tag called ‘q1 computer sale’. Any product with that tag will use the Price Card pricing.

Break Quantity Pricing: In pricing, break quantity is a concept where the pricing of the product varies based on how many of the same item is bought. Once Snapshot is created, you can add currency specific pricing by clicking on the ‘Add’ link in the dropdown on the right. When you add the currency specific pricing, you can create Break Quantity Pricing as shown in the below screenshots.

Once pricing are added you need to request for approval using the dropdown menu and approver needs to approve the price. Only user with Pricer role can create the pricing and user with Pricer Manager role can approve the price.




Once you defined the Pricing, you can go to the Product and select the Pricing Card, like below.

Customer Specific Pricing: Customer specific pricing is important in B2B commerce and heavily used. Often, B2B clients negotiate price with manufacturer or seller and commerce application provides ability to implement the complex pricing. Sitecore Commerce doesn’t support customer specific pricing out of the box at this time. It will be a good feature to add. Although customer specific pricing is much needed in B2B commerce, in my experience, 60 to 70 percent time, our clients want to use already existing pricing logic in ERP. In such situation, we create an integration with ERP to fetch the price real time.

Overall, Sitecore Commerce provides pretty flexible and comprehensive pricing  features. With the new Plugin architecture the pricing framework can be extended for the purpose of any unique requirements.

Posted in Commercce | Tagged , | Leave a comment

Notes from Sitecore Commerce Installation

Finally, I found some time to install Sitecore Commerce. I am excited because, I can play with it and see why everyone in Sitecore Community is talking about it. First of all, installing Sitecore Commerce is quite a complex task, at least for now. It is going to get better that’s what I heard.

First challenge was, where to start. Sitecore has provided Sitecore Commerce 8.2.1 Deployment Guide. It’s pretty comprehensive but, I took a easier path. It’s easier to learn from someone who has done it already and especially, if he has made a video of that. Along with this video Sen Gupta  put together a blog article too.

The video and the document was immensely helpful. But, I did face some issues, mostly, due the configuration of my machine. I am going to describe those issues in this blog and also, talk about how the configure the storefront source code, so that, we can debug the code and learn how Sitecore Commerce architecture works.

Here are the issues I faced.

 Cannot start IISAdmin
I got this problem because ‘Internet Information Services\Web Management Tools\IIS 6 Management Compatibility’ Windows Feature was not turned on.


Commerce Server was unable to create a Registration Marker in Active Directory
I got this error but, it seemed to me that it is normal because my computer is not a domain controller or connected to any active directory. I ignored this message.

Adding the identity ‘domain\myaccount’ to the AzMan role ‘Administrator’…
New-CSWebService : The server could not be contacted
I Got this error but, I was not sure why powershell script is trying to add my login account in Authorization Manager. My login account was not used to run any services. I ignored this. I did manually add the ‘Administrators’ group and ‘CSFndRuntimeUser’ in the Role Assignments in CatalogAdministrator. It can be done by opening up the AzMan.msc console.

Issues with not having SQL instance as the default instance
I had many issues because my SQL Server 2014 is not a default SQL instance. I had to change in the following places
Installing DACPACK: I had to change /TargetServerName:SQLServer\InstanceName Connection string: In the following json files I had to change “Server”: “.” with “Server”: “SQLServer\InstanceName”. Without this change Commerce Authoring bootstrap was throwing error, ‘HTTP Error 502.3 – Bad Gateway The specified CGI application encountered an error and the server terminated the process.’ I had to make that change in the following files

PlugIn.AdventureWorks.CommerceAuthoring-1.0.0.json PlugIn.AdventureWorks.CommerceMinions-1.0.0.json PlugIn.AdventureWorks.CommerceShops-1.0.0.json
PlugIn.Habitat.CommerceShops-1.0.0.json CommerceAuthoring\wwwroot\bootstrap\Global.json

Service Url issue
All above json files had “ServiceUrl”: “http://localhost:1004. I had to change that to “ServiceUrl”: “http://csservices:1004, because “ServiceUrl”: “http://localhost:1004 was not accessible. Other way to fix this is to add a iis binding for CommerceAuthoring site with empty host name.

Storefront Solution Setup
I setup the reference storefront solution, so that, I can debug code and understand the architecture. The source code is available here. Download Reference-Storefront-10.0.853.

Storefront\CF\CSF contains the Sitecore Commerce storefront source code
Storefront\CS\CSF contains Commerce Server storefront

Following Changes are needed to compile and deploy the code successfully.

  • Change project properties of TDSCommerceEngine_Master to point to the storefront website
  • Change project properties of TDSCommon_Master to point to the storefront website
  • In Commerce.Storefront project change the hostName for the storefront in the site node
  • Copy all sitecore dlls from Storefront website bin folder to Storefront\Lib\Sitecore in your solution including the following dlls.
    ComponentArt.Web.UI.dll (remove and add reference in the project)
    System.Web.Http.dll (remove and add reference in the project)
    System.Web.WebPages.Deployment.dll (remove and add reference in the project)
    System.Web.WebPages.dll (remove and add reference in the project)
  • Some references from Nuget packages were not picked up. I had uninstall and install those Nuget Packages.
  • Copy GlobalSuppressions.cs from Common project to Commerce.Storefront project

Build and deploy the project and start learning 🙂

Posted in Commercce, Commerce Connect, Sitecore | Tagged , | Leave a comment

Custom Theme MVC View Engine for Sitecore Multisite Implementation

Custom MVC view engine for extending theming in the MVC application is a well discussed topic. You will find it in many discussion forums and in many blog posts. The problem in question is, how can you extend the theme of your MVC application from a base theme, so that if you want to extend certain pages in your application, the child page should override the base page. The most well known solution is to create your own View Engine with ordered view and partial view locations and Insert your View Engine as the first item in the View Engine collection. This way MVC will find your View Engine first and find the views as you desire. Here are some code example.

    public class CustomViewEngine : RazorViewEngine
        public CustomViewEngine()
            var themeName = ConfigurationManager.AppSettings["ThemeName"];
            var baseThemeName = ConfigurationManager.AppSettings["BaseThemeName"];
            Assert.ArgumentNotNullOrEmpty(baseThemeName, "BaseThemeName");
            if (!String.IsNullOrWhiteSpace(themeName))
                ViewLocationFormats = new string[] { "~/Themes/" + themeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + themeName + "/Views/Shared/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                PartialViewLocationFormats = new string[] { "~/Themes/" + themeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + themeName + "/Views/Shared/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                ViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                PartialViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };

If the ThemeName is not empty, then ViewLocationFormats and PartialViewLOcationFormats contains the ThemeName folders path first on the order and then the BaseThemeName folder path. That ensures, when there is a view available in the ThemeName path, that will be rendered, otherwise, the view from the BaseThemeName path will be rendered.

Now we have to add this custom view engine to the View Engine collection.

ViewEngines.Engines.Insert(0,new CustomViewEngine());

Usually you will do this in global.asax Application_Start event method or  WebActivator’s PreApplicationStartMethod.

This works fine, when you have developed a base website and then you customize that website for many implementation. But, at a time you have only one site.

Now, consider this situation, when you have to implement multiple sites in the same Sitecore instance and each site can have a different theming from the base theme. In this case, you will have multiple theme folders and those folders can contain the same views or partial views. If you add all these theme folders in the view location, MVC will render the one that is on top in the order, not the one that you intend it to do. How to solve this problem?

First of all, we need to know what’s the correct theme for a site in the multisite scenario. This is not difficult. We just put the theme name in the SiteDefinition.config in the site node as custom attribute ‘themName’, like below.

<configuration xmlns:patch="">
      <site name="site1" patch:before="site[@name='website']" 				 enableTracking="true" 				 hostName=""          virtualFolder="/" 				 physicalFolder="/" 				 rootPath="/sitecore/content/site1" 				 startItem="/home" 				 database="web" 				 domain="extranet" 				 allowDebug="true" 				 cacheHtml="true" 				 htmlCacheSize="50MB" 				 registryCacheSize="0" 				 viewStateCacheSize="0" 				 xslCacheSize="25MB" 				 filteredItemsCacheSize="10MB" 				 enablePreview="true" 				 enableWebEdit="true" 				 enableDebugger="true" 				 disableClientData="false" 				 cacheRenderingParameters="true" 				 renderingParametersCacheSize="10MB"          themeName="site1theme"     />
      <site name="site2" patch:before="site[@name='website']" 				 enableTracking="true" 				 hostName=""          virtualFolder="/" 				 physicalFolder="/" 				 rootPath="/sitecore/content/site2" 				 startItem="/home" 				 database="web" 				 domain="extranet" 				 allowDebug="true" 				 cacheHtml="true" 				 htmlCacheSize="50MB" 				 registryCacheSize="0" 				 viewStateCacheSize="0" 				 xslCacheSize="25MB" 				 filteredItemsCacheSize="10MB" 				 enablePreview="true" 				 enableWebEdit="true" 				 enableDebugger="true" 				 disableClientData="false" 				 cacheRenderingParameters="true" 				 renderingParametersCacheSize="10MB"          themeName="site2theme"     />

We need to override two methods FindView and FindPartialView in our custom view engine. In these methods, we need to read the themName for the site in the current sitecore context and return the appropriate view ViewEngineResult.

    public class CustomViewEngine : RazorViewEngine
        public CustomViewEngine()
            var baseThemeName = ConfigurationManager.AppSettings["BaseThemeName"];
            Assert.ArgumentNotNullOrEmpty(baseThemeName, "BaseThemeName");
                ViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                PartialViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
            if (controllerContext == null)
                throw new ArgumentNullException(nameof(controllerContext));
            if (string.IsNullOrEmpty(viewName))
                throw new ArgumentException("viewName");
            var currentSite = Sitecore.Context.Site;
            var themeName = currentSite.Properties["themeName"];
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            if (!string.IsNullOrEmpty(themeName) && !viewName.Contains("/"))
                var viewPath = $"~/themes/{themeName}/views/{controllerName}/{viewName}.cshtml";
                //If the view file doesn't exists in the folder look at the shared folder
                var absolutePath = HttpContext.Current.Server.MapPath(viewPath);
                if (!System.IO.File.Exists(absolutePath))
                    viewPath = $"~/themes/{themeName}/views/shared/{viewName}.cshtml";
                    absolutePath = HttpContext.Current.Server.MapPath(viewPath);
                    if (!System.IO.File.Exists(absolutePath))
                        throw new Exception(string.Format("View {0} doesn't exists.", viewName));
                return new ViewEngineResult(this.CreateView(controllerContext, viewPath, string.Empty), (IViewEngine)this);
            return base.FindView(controllerContext, viewName, masterName, useCache);

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
            if (controllerContext == null)
                throw new ArgumentNullException(nameof(controllerContext));
            if (string.IsNullOrEmpty(partialViewName))
                throw new ArgumentException("partialViewName");
            var currentSite = Sitecore.Context.Site;
            var themeName = currentSite.Properties["themeName"];
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            if (!string.IsNullOrEmpty(themeName) && !partialViewName.Contains("/"))
                var partilaViewPath = $"~/themes/{themeName}/views/{controllerName}/{partialViewName}.cshtml";
                //If the view file doesn't exists in the folder look at the shared folder
                var absolutePath = HttpContext.Current.Server.MapPath(partilaViewPath);
                if (!System.IO.File.Exists(absolutePath))
                    partilaViewPath = $"~/themes/{themeName}/views/shared/{partialViewName}.cshtml";
                    absolutePath = HttpContext.Current.Server.MapPath(partilaViewPath);
                    if (!System.IO.File.Exists(absolutePath))
                        throw new Exception(string.Format("View {0} doesn't exists.", partialViewName));
                return new ViewEngineResult(this.CreatePartialView(controllerContext, partilaViewPath), (IViewEngine)this);
            return base.FindPartialView(controllerContext, partialViewName, useCache);


That’s it! Happy coding.

Posted in MVC, Sitecore | Tagged , | 1 Comment

Inbound Marketing with Sitecore – Social Media

In the last blog post, I discussed about importance of engagement in SEO. One of many ways to engage users to the site is to use social media. In this blog post, we will talk about role of social media in Inbound Marketing and how Sitecore can help with including social media in a Sitecore implementation.

Let’s start with some statistics to understand why social media is so important for Inbound Marketing.

  • There are more than 2 billion social media users worldwide
  • In 2016 68.3% internet users are social media users
  • 9 out of 10 US business actively use social media
  • 1 in every 5 page views in internet is Facebook

I can go on and on with more statistics but, it suffices to say from the above,  businesses have to include social media in the core  strategy.

Social Media Strategy

For effectively amplifying the content in social media, there need to have a clear strategy. Here are few things, that we need to consider for creating a solid strategy

  • Choosing an appropriate social media platform is very important. We need to look at the buyer’s personas of the company to understand which social media platform is most effective to amplify the content. For example, if your company is in professional services, LiknedIn is a good choice, whereas, if you sale products, Facebook might be mpre appropriate platform.
  • If you are using multiple social media platforms, the buyer’s personas can be quite different from one platform to other. In this case you need to optimize the content on the basis of what social media we are using.
  • There need to have a clear measurable and attainable goal. We need to set goal on how many content will be shared, how many  unique visits we want to achieve from social media and how many of visitors we would like to see converted. This will be useful to understand the ROI.
  • The content that will shared in the social media should be consistent towards establishing the brand of the company. Content should be written such a way so that, users recognize the brand at a glance. This will have lasting effect on users and they will come back to the site repeatedly.
  • It was found that content with relevant images get 94% more views than content without relevant images. Images and videos can help you reach to bigger audience. You can use site like Cavana or Pablo to create visual images for your content that you share in the social media.
  • Find the optimum time to publish your posts on the social media. If your audience is teenagers, good time to publish the post maybe after 3 afternoon because that’s when the school breaks. But, if the audience is middle aged people, maybe the best time is evening 7 o’clock.
  • Finally, all social media provides analytics data to understand user engagement. For example, following is a screenshot of analytics data from my Twitter account. You can use data from social media to understand user engagement to your site and contents.

Twitter Analytics

Integration with Social Media

There are three different ways a website can be integrated with a social media platform.

  • Content can be shared by placing social media button on the web page. In this case if the user click on the social media button the content will show up on the wall in the social media site.
  • Site can use social media to authenticate to your website. In this case you can access users social media profile and learn more about their activities in the social media.
  • Most companies have their own social media pages. Users may consider to follow the company in the social media and that way visit to website contents directly from the social media pages.

Sitecore Social Experience

Sitecore currently provides two options to integrate with social media.

  • Komfo – Komfo is a Danish company with Social Media Marketing Suite of products that let you publish, listen, monitor and analyse social media data. Sitecore Komfo connector let you connect to social media using your Komfo accounts and manage and harvest the social media data from within Sitcore. The social media campaigns can be tracked Sitecore Experience Profile. Access of users social activities enable Sitecore to personalize users experience in the website. Based on users activities captured in the experience database, targeted ads can be published to social media through Komfo connection.
  •  Sitecore Social Connect – Sitecore Social Connect is a in-built social media connector in Sitecore that let you communicate with social media platform Facebook, Twitter, LinkedIn and Google+. The API can be used to authenticate to the social media. You can import the user data from social media to Sitecore Experience Database and use that for personalization purpose. You can publish content to social media channels from Sitecore. This is a free option.

Besides the above two options for social integration, Sitecore also integrates with Telligent Community application. But, Telligent is not for mainstream social media platforms, it is to create a social community for customers of a company or employees within a company. Sitecore integration with Telligent let you analyse and personalize the website for you customer or employees.

As mentioned in the last post social media conversation helps with SEO too as user engagement is one of the factors in SEO ranking. So social media staregy is extremely imporatant for lead generation in Inbound Marketing.  Social media is innovating and changing everyday, marketing has to keep up with that. We hope to see innovations in Sitecore too to keep up with social media changes.


Sitecore Social Marketing Experience

Posted in Uncategorized | Leave a comment

Inbound Marketing with Sitecore – SEO

The first step of Inbound Marketing Methodology is to attract people to the website or to content they are looking for. How people are going to try to find contents that they are trying to find out? If I ask this question to someone today, most people will say , ‘I will google it’.

Here are some data from my own blog. For the month of September 2016, there were 1024 visits to my blog site. Out of that 1024 visits, 645 came from Search Engines, that is 63% of total visit. It’s also noticeable that most people searched in Google and so if I keep our SEO best practices discussion around Google, we should be able to cover most important topics.

Site Stats

Site Stats

Not to brag about my blog but, this gives us some idea about, how important it is to use SEO properly. Currently search engines reach 67% of the US population and 98% of the US browsing population. Any website with good attention to SEO will show advantages as far as Inbound Marketing is concerned.

In this blog article, I will discuss implementation of SEO for websites built on Sitecore. There will be lots discussion about SEO best practices. Sitecore will be discussed at the end. I will discuss about Sitecore information architecture and Sitecore tools that can help us to  apply the SEO best practices in a Sitecore implementation project.

We should keep in mind that, Google is always changing the search engine algorithms, something relevant today, may not be entirely relevant tomorrow. My focus in this article is to provide the information that will help someone to understand SEO in the context of Inbound Marketing and how to implement those SEO best practices in Sitecore.

What happens when we search in Google? Google algorithm search through the indexed documents and try to find out best possible match for the search criteria. How that works? Here is a short video by Matt Cutts on how Google search works.

In addition to finding the best content, Google also try to present the search data in many interesting ways to intrigue users. As much as it is important to understand how search works, it also important to understand how Google present search results. Each search result Google shows is called a snippet. Understanding snippet will help us to understand where Google find these snippet information and hence we will be using that to intrigue our buyer personas to attract them to our website. Again, here is a video by Matt Cutts where he explained result snippets.

The video is little old, but it is still relevant. Google, since has added many more interesting features to its search presentation. For best SEO result for the Inbound Marketing, there are two things that are most important, 1) achieving high search ranking and 2) achieving high click through rate by proper use of Google’s presentation features. Let’s dive into our journey.

Domain Name Selection

Good strategy for SEO starts from very beginning of the project. What’s going to be the domain name of the website? It is important to put some thought on that, because domain trust is important for SEO. When it comes to choose domain name, consider following

  • The domain can be based on brand name or based on keyword. Google value the brand name. Having the EMD (Exact Match Domain) in the domain name doesn’t affect ranking in Google but, it might help with other search engine. From the SEO perspective it is best bet to establish a brand name for the long run. In the Sitecore world most of the time the implementations are for some sort of business and having a brand name makes sense.
  • What about domain extensions? Google doesn’t give any preference to any domain name extensions but Bing does. In bing .com gets the preference. The .com extension is most popular and most desirable to searchers. Getting a .com may help a bit more than other domain name extensions.
  • Keep your domain name length less than 15 characters. Shorter domain name is easy to remember, easy to share and less chance of typos.
  • Avoid using too many hyphens in the domain name. Sometime using hyphen helps if you are using keyword driven domain name, but in general avoiding keyword in the domain name is a good practice.
  • If  you are looking to register a domain name and you find a domain name that matches with your brand was already register, it might be beneficial if you can acquire that domain name. Old domain name might get a better search ranking because of the trust it already built with the search engine. You can check the trust of the domain using Majestic SEO and power of the domain by using Moz’s Open Site Explorer site rating. I discussed these two tools in later section. Also, it doesn’t make sense to acquire domain name which doesn’t close to your brand. Some sites you can use to check for the old domain name are SEDO, GoDaddy Auction, AfterNic, DomainTools.
  • There are some good domain name generator tools out there which you can use to help you with deciding a domain name. Check out,

Content writing for effective SEO

It’s a cliche but, I will say it, Content is the King. It is a misconception that content is the only thing that Google considers for the ranking. What Google’s aim is, to find out how trustworthy the content is and for that it needs to also look at the engagement. We will talk more about this later. But, quality of the content is really important. How do we create quality content?

  • Most Important thing to remember about optimizing content for search engine is that, you are creating your content for the readers and it should be optimized for the readers. If you focus too hard for the good search ranking of your content, you may fail to deliver the message effectively to the target consumer of your content. Being said that, you want your readers or Buyer Personas to find out your content and for that you need to think about how the Buyer Personas will search for the content, what keywords they will use. We will discuss about how to choose good keywords, in the next section.
  • When it comes to quality of content, Google doesn’t look at only one page of the website. Google looks at the whole domain to determine the authority and reputation of the website. What determines Authoritative Content for the search engine? Trust. More the content cites trusted sources, linked by trusted sources, published in trusted sources, written or reviewed by trusted author, more is the authority of the content. Google determines the Reputation of content by measuring the user engagement with the content. Some of the criteria Google looks at are, bounce rate (how much time user is spending on the content), social sharing metrics, website performance, user’s trust on the website etc. Using Magestic SEO, we can measure the Trust Flow and Citation Flow of a website. So before using link to a source website or approach someone to link to your content, the trust can be measured using Magestic SEO. Here is an example of Trust and Citation flow for
    Magestic SEO
  • Use clearly descriptive and concise anchor text so that, user and google understand what page the link is navigating to. Make sure the anchor text can be differentiated from regular text so that, users don’t miss it or accidentally click on it. Use anchor text for linking internal pages too so that, user and google can navigate to different part of the site naturally. Do not go overboard with internal linking. Only relevant internal links should be placed.
  • I mentioned before, Google checks the bounce rates to determine engagement with the content. It is important to write content that can be read easily. Use short sentences. Try to keep in 15 to 20 words. Keep the paragraph short. Use a structured layout for the content. Discuss different topics in different section of the content.

Keyword Research

There is a myth that, keyword research for SEO is useless. It was proven by many case studies that finding out good keywords helps with search ranking. Google will eventually crawl the content but, with so many contents out there, choice of right keyword will help with staying ahead of the competition.

  • Keywords or phrases are search terms that users search to find information they are looking for. Predicting the search term or the keywords, that will be entered by readers of the your contents is extremely important for the search ranking of your web pages or blog posts. Start with a list of 10 keywords for your content and use a Keyword research tool like SERPs Keyword Research Database to see the competition for the keywords in google. You can use rank checker SERPs Keyword Rank Checker to see how the websites are ranking based on the keyword you have used.
  • Instead of using short keywords, use long tailed keywords, which will have more probability to give you better ranking because short keywords will be there in most sites. For example, instead of ‘Carbonator Motor’, use something ‘Carbonator Motor for Soda’ if you are writing about that kind of motor.
  • When it comes to choose keywords for a content, first choose an appropriate Primary Keyword. Then select some supportive keywords. You need supportive keywords for placements in the page. You may want to put the primary keyword in the content and the supportive keywords in the Title of the page and in the URL. Supportive keywords helps to avoid over optimizing contents. Google Adsense is a great tool for finding supportive keywords.
  • There is no need to add keywords in the Meta Keyword tag. Google doesn’t use Meta Keyword at all for ranking.
  • Bolding words using <strong> or <b> element doesn’t help with search ranking. It helps users to read the article, if you want to emphasis certain words in your content. That way it helps with engagement. Same is true for <h1> and other heading tags.
  • Keyword density in a content is something you should be aware of. Using keywords too many time in the content can cause over optimization and that can hurt search ranking. Recommended number of keywords in the page should be between 3 to 7.


Search Engine’s ultimate goal is to provide contents that people would like to see. How do the search engine know if people woud like a content? The answer is, by monitoring the conversation. It’s like real life, when we like a book, we talk about it with our friends, spread the word. Similarly more the content reach to more people, via different channels like, blogs, social media, email etc., it indicates more people liking, more conversation. So, quality content is not the only thing that matters for search ranking. How people are engaging with the content and how the content is getting distributed is something that search engine looks at today.

If the content is good and it becomes popular, more people will link to the content. Google search ranking consider this as a factor for search ranking. The dark side of ranking based on links from other sites is that, people try to game the system. Tell bunch of people to write some content and link to their site with the sole purpose to game Google search algorithm. Google doesn’t like it and there are many incidents where Google penalized websites for trying to game the system. You will find some examples here .

Whether you are linking to some source content or someone is linking to your content, it is important that those links have high trust value. A good place to check the trust of a link is to use Majestic SEO website as we discussed before in this article.

Listing the site in the directories can improve the search ranking but you need to be careful about the quality of the directory service and you need to have right strategy to implement this for your website. Here is a nice article about directory listing.

One thing to consider about link building is that, the link building should naturally grow. It’s not natural that we write a content today and hundreds of sites immediately linking to the content. If that happens, Google will consider that as suspicious.

Guest Blogging can help with search ranking but, you need to be careful because, guest blogging is only effective if it helps building the trust. First of all, the content written by guest blogger should be relevant and quality content. You should use guest blogger who has acquired some authoritative trust from Google. If you have a circle of quality blogger writing on the common interest, it will help with engagement for the community, which helps adding popularity for the content. When it comes to distributing the content, it can be distributed through different medium like, infographics, ebook, audio, video etc.

Since search ranking is influenced by the engagement towards the content. Distributing content through social media is important. Always use social sharing icon in the article. Have social networking accounts for the business and make sure the sites are publicly viewable.

Search Result Presentation

Search result presentation is as important as search result ranking. It often happens that user clicks on the third ranked search result because it’s snippet is showing some text that are relevant to the search.


What we add in the <title> tag of the page shows up as the title in the search result.

  • Choose a title of the page that describes the content of the page accurately.
  • Don’t use the exact target keyword in the title. Google penalize websites that tries to over optimizing for search engines. We discussed about the Primary Keyword and Supportive Keywords. It is preferable to use a Supportive Keyword for the title.
  • Don’t use same title for multiple pages in the site. Search engine consider duplicate titles as malformed and penalize.
  • Use short descriptive title. There is a fair chance that title will be truncated after 62 characters. Shorter title has higher click through rates.

Meta Tag Description

Adding text in the meta tag description gives you a chance to show the user what you want to convey about the content. If the text is relevant to what user is searching, there is a fair chance that Google will use that. If there is no meta tag description, Google will look at the content and construct the snippet. Google may also look at the open directory for the snippet text.

  • You can tell google to not to look at open directory by using <meta name=”robots” content=”noodp, noydir”>
  • Accurately describe the page. Meta tag description run about 155 characters. User will look at this snippet and decide whether the actual content has information they are looking for. It is very important to use the words wisely to attract the users to your content.
  • Use unique description for each page. If there are huge number of pages it is better to automate the creation of meta tag description. For example, for a ecommerce site there can be thousands of products. In this case meta tag description of product detail page can be built from product description. This is true for title too.

Structured Data Markup

The Structured Data Markup is an effort by internet community to organize data in a standard structured way to present the data to online visitors. The Structured Data Markup schemas are available in Every website has some sort of structure data. For example, if the website is a travel site, it can provide Structured Data Markup of type ‘Place’. If website provides Structured Data, Google and other search engine might present that data in a interesting way along with the search result. For example, if I search for Norah Jones, along with the Norah Jones’s site link in the search result, Google also show the event information tothe right.

Structure Data are mostly presented  in JSON-LD (JavaScript Object Notation for Linked Data) format. Following is an example of structured Data of type ‘Product’ in JSON-LD format.

“@context”: “;,
“@type”: “product”,
“brand”: “Canon”,
“name”: “5D Mark III”,
“image”:             “;,
“description”: “Great SLR Camera”,
“aggregateRating”: {
“@type”: “aggregateRating”,
“ratingValue”: “4.5”,
“reviewCount”: “456”

In web page, Structured Data needs to be included in header section within script tag as above example. Structured Data don’t help increasing search ranking but definitely help with the click through rate. To find some examples of Structured Data in Google, you may search for some recipes and you will see the Structured Data about recipes presented with images, ratings etc. To see what Structured Data is included in the site,  use Google’s Structured Data testing tool. Entering the website Url will show the Structured Data in nice format. If the Structured Data is one of the qualifying content type, Google will show them in rich snippets. You can learn more about Structured Data here .

Other Important Topics

There are many other aspects of website either help with the ranking or click through rate directly or indirectly. Let’s discuss them.


  • Simple-to-understand url helps user and search engine to understand the url and return effective result. Google returns the url as part of the search result snippet. If the url is simple, it is easy for the user to remember and increase the probability that user will visit the same page again.
  • Choose Url with words relevant to content. We talked about supporting keywords. Using a supporting keyword is a good idea.
  • Create simple directory structure. For example, all product detail page should show url like, Avoid deep directory structure and directory name not relevant to the content.
  • Use one version of url in the site. If you have old version of url that users are still using, use 301 (permanent redirect) or 302 redirect to redirect old url to the new url. If you know that the old url will never be used again use 301. If you feel that old url can come back in future use 302.
  • If you have deleted a page completely and there is no alternative page for that, the URL will be broken and the web server will return 404, page not found. If you know the content is deleted forever, you should return 410, that will tell google that this content was deleted and Google will remove that from the index.
  • Use lower case in url. It is easy for users to remember.

Canonical URL

Use Canonical link element when there are more than one version of the same content. The canonical link tells search engine which link to consider for ranking when even the visitor lands to a different version of the page. The canonical element is declared like <link rel=”canonical” href=””&gt;. Even when there is only one version of the page, we should use canonical element because the same page can be rendered when there different parameters included in the URL. Google also considers self referencing of a URL in the canonical link as the best practice. If there are duplicate pages in the site instead of using canonical link, you should remove the page and use 301 redirect. You should be careful about the canonical link. If the canonical link is not a valid link the search ranking can affect severely.

Site Navigation

  • Navigation should be simple to understand for user and have naturally flowing hierarchy.
  • Use text navigation mostly and avoid image, animation link as much as possible.
  • Create a simple html site map page for user and a XML site map file for search engine.
  • Use custom 404 page to provide friendly message to user in case user come across a link or page that doesn’t exists.

Image Optimization

  • Always use a descriptive alt text for image. This will help your image to be added in the google image search. If the image is used used for linking, alt text will be used like anchor tag.
  • Use distinct name for each image.
  • Store images in one website folder than creating multiple folder hierarchy to store images. In case of Sitecore images are stored in the media library. Make sure the media library path is simple.
  • Use right image type (jpg, png etc.) in the image file name.
  • If there are numerous images in the website, include a image sitemap file. The format of the image similar to XML Sitemap file.

XML Sitemap

A Sitemap is a XML file that describes the structure of the site. Search engines can use it to find out pages/images/videos to crawl. There are some debates if Sitemap file is needed for Google to find out the pages of the site. It is true that Google can find out and crawl pages even if the Sitemap file doesn’t exists but, Google highly recommends to have Sitemap file for several good reason.

  • If the site is too large, it is possible that some of the pages will be overlooked because those pages are not linked from other places in the site.
  • The site is an online ecommerce site with huge number of products. It is quite obvious that Google will not find all the product url and will not index.
  • If the site is new and it is not linked by external site, Google wouldn’t find it.
  • If there are archived pages in the site and if the pages are not naturally linked to each other, Google will overlook those pages.
  • Other than the location of pages, Sitemap also provides meta data information like, when the page was last updated, how often this page changes, what is the importance of the page compared to other pages etc. These information helps Google with crawling and indexing.

There is a limit for the Sitemap file size. A Sitemap file can be at most 50 MB uncompressed and can have less than 50,000 urls. After that you have to create multiple Sitemap files. There are two different ways you can let Google know about the Sitemap:
Submit it to Google using search console Sitemap tool or add the Sitemap file location in the robot.txt like, ‘Sitemap:;.

Following is an example of a Sitemap that contains only one URL.


Block Content from Search Engine

Sometime you don’t want some content to show up in the search result. Typically we want to exclude content that contains private information of customers or users. There are several ways to prevent content from search crawler.

  • If the site is designed with authentication, Google will not be able to get to the content. If authentication is not there, best way protect content is to password protect the folders.
  • If it is not matter of privacy, but we don’t want the search engine to not crawl certain areas of the application, we can use robot.txt. Typically, we don’t want search engine to crawl files like images, stylesheets, scripts etc. Doing this will save resources for both the website and for the search engine. Remember, excluding files using robot.txt, will not protect files from showing up in the search result. Files can still be crawled, if the files are linked from other places, which were not added in robot.txt. Learn more about robot.txt from Google.
  • NoIndex and NoFollow – noindex is used in the robot meta tag, search engine will drop that link or page from the index. It is a week way to prevent a content because sometime we may forget to add this and as a result content will show up in the search result.
    Setting nofollow will tell google to not to crawl any link in that page. There are times we want to put a link on the site but don’t want to pass the reputation. For example, we are putting some website links which we know are are not quality site. In this case we would like search engine to not follow the link because it might hurt the reputation.
    Here is how we should use nofollow and noindex for all the links in the page,<meta name=”robots” content=”noindex, nofollow”>If you want not to index a specific link in the page you can use NoFollow in the link element like below<a href=”; rel=”nofollow”>nofollow link</a>


Does having SSL helps in search ranking? It’s hard measure if it helps, but Google says so.
There are definitely some advantages besides the search ranking.

  • Having https in the site provides a sense of security to visitors and it
    protects visitors’ communication with the site and protects site from the ‘man in the middle’ attack.
  • Without https, when users come to your site from a https site, you will not see the referring site and that is an analytical disadvantage.
  • When you move to https, we should update links in sitemaps, resgister https link in Google webmaster tools and make sure to use 301 redirect to redirect http links to https links.
  • It is preferable to use HTTP Strict Transport Security (HSTS). This will remove the requirement of 301 redirect and speed up the application performance.

Website performance and Uptime

Website performance can hurt the search ranking.  Google devalue website, if performance is bad. There are many ways you can achieve the best performance of the website, one of them is to use caching efficiently. You should also be careful about the javascript used in the website. It is a good idea to include script at the end of the webpage for the efficient loading of the page. Careful about using social button and third party javascript because they can hurt the performance if the sites they connect to have performance issues.

The quality of the website suffers in the eyes of search engine if website crashes or hangs. If pages are moved or deleted, use 301 redirect to appropriate page or use status code 410 to let Google know the page was deleted permanently.

Sitecore Information Architecture Consideration for SEO

One of the biggest challenge of SEO implementation is to constantly  maintain and follow the SEO best practices for the site. A proper Sitecore information architecture can help with this significantly in regards to ease the implementation and enforce the best practices.

SEO Template

To support and enforce SEO for any Sitecore project, I suggest to create a SEO template and include this SEO template as one of the parent templates of the page template. The SEO template can contain following fields.

SEO Template


  • The Title contains the title of the page that gets placed between <title> element of the page and shows up in the Google snippets title. You should consider to use a supportive keyword for Title to prevent the page from over optimization.
  • Meta description is the field where you want to add the summary of the content. This will be displayed in the Google snippet summary, if Google finds it suitable.
  • Url field is to add the keywords you want to see in the page Url. By default Sitecore Link Manager generates the Url from the item name. But, as we discussed before, it is good idea to use a supportive keyword for Url to properly optimize the page. It also gives an opportunity to the content editor to change the Url after the items are created. To use this Url field to generate Url of pages, you need to create a custom link Provider. One word of caution about using this separate Url field is that, you should not change the Url field frequently, because, once site goes live, the Url will be indexed by search engine and people will start using it. If you change the Url, the old link will be broken. In case you need to change the Url, you should use 301 redirect for the old Url.
  • I discussed before about the Structured Data Markup and how it helps presenting the result in Google search. If the website presenting content that qualifies the Structured Data Markup types, it is highly recommended to use Structured Data in the SEO items and generate the JSON-LD script to add in the page head section.

SEO Field Validation

Sitecore allows you to apply validation to the fields of a template through field validation rules. There are many validation available in the base product as shown below. You can also create custom validation rules.

Sitecore Validation Rules

You can select a validation rules for the SEO fields to enforce good SEO practices. Here, I selected the required and Max Length 40 for the Title field.

Sitecore Validation Rules

When I create an Item that doesn’t satisfy the validation rule, Sitecore will show the indicator and message that the item has some validation failure. Like below it is showing on the Quick Bar on the left and next to the item field.

Validation Result

Validation rule can also be run from the Review panel in the content editor.

You can create some custom validation rules like, the Title field and Url field cannot contain the same text. This will ensure SEO optimization rules.

Image Optimization for SEO

In Sitecore the images are saved in Media Library. When images are access for a web page Sitecore will render images using ASHX handler. In the Media Library item for a image there several fields you can enter values. One of them is Alt in the Image section for Alt Text. This field has validation and shows red line when no text is entered. Below is an example.

sitecore media image

The Sitemap generator mentioned below can be extended to generate Sitemap XML for all images used in the website.

Sitecore Experience Accelerator (SXA)

Sitecore Experience Accelerator (SXA) is newly added module in the latest version of Sitecore. SXA has some neat features to improve SEO. You can enter the title and meta description for page items. It does have a field for meta keywords, which has no effect on search ranking. The nicest feature in SXA is, you can enter the Sitemap data in the page item and generate the Sitemap file for the website. Learn more  about how to Improve page SEO in SXA.

Sitecore Tools for SEO

There bunch of tools available in Sitecore Marketplace, can be useful for SEO implementation.

301 Redirect Module
There two 301 redirect modules available in Sitecore Marketplace. These modules provide varieties of feature for 301 redirect.

Sitemap Generator
Checkout the following Sitemap generator modules.

Sitecore SEO Toolkit
Sitecore has a free SEO toolkit that can be useful to evaluate SEO related problems in the page content. The SEO toolkit can be integrated with third party APIs for keyword suggestion and content analysis functionality. This tool was not updated recently as per the newer version of Sitecore. You might face some issues if you are using Sitecore version 8.0 or up.

Final Thoughts

In this article I tried to cover most of the important best practices of SEO. Hopefully, this will help marketers and developers to understand SEO in the context of Inbound Marketing and how to use Sitecore efficiently to achieve the SEO goals. As a platform Sitecore is very flexible and extensible. There are opportunities of creating many more tools to help with SEO implementation for Sitecore projects. I have plans to create some tools and I am looking forward to see more efforts from the community.

Posted in Inbound Marketing, SEO, Sitecore | Tagged , , , | 1 Comment