Published: 14 December 2015
We have a superb in house SEO team, so when I attended my first Sitecore certification I was keeping an ear out for things that I thought would lead to problems.
One issue that stood out in the training was that a single page can have multiple URLs. You don't need to be an SEO coding God to know that multiple URLs are bad.
Create a new page in Sitecore called “Sample Item“ it can be accessed using these URLs out of the box.
having four version would be bad enough but it gets worse. The urls can vary by case as well so “Sample” is different to “SaMple”. So each url gains two versions for every letter in the item name.
The first thing to do is before even starting the build is to update the linkManager tag.
<add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="asNeeded" languageLocation="filePath" lowercaseUrls="false" shortenUrls="true" useDisplayName="false"/>
Make sure that languageEmbedding is set to “always” or “never”. The built in link manager has an annoying habit when using asNeeded to swap between the /en or normal prefixed URLs. LowercaseUrls should be set to true so that when links are generated they are always lower cased. Another issue as you may have noticed in the URLs above is that Sitecore allows spaces in URLs and then encodes them as %20. You can get around this by patching encodeNameReplacements.
<replace mode="on" find=" " replaceWith="-" />
The above changes will help make sure that the in built URL generation will output URLs which are consistent. Of course if you are using a custom URL generator then the above changes might be ignored. Also it doesn't mean that if you manually type an invalid URL into a browser or those URLs are in the wild it will not fix the issue.
To ensure that the multiple URLs are converged you will need a Sitecore processor. Here is an example.
public class InvalidUrlProcessor : HttpRequestProcessor
public override void Process(HttpRequestArgs args)
var Request = args.Context.Request;
var Response = args.Context.Response;
var item = Context.Item;
string ItemUrl = LinkManager.GetItemUrl(item);
string CurrentUrl = Request.RawUrl;
if (ItemUrl != CurrentUrl)
Response.Status = "301 Moved Permanently";
protected virtual bool IsValidContextItemResolved()
if (Context.Item == null)
return !(Context.Item.Visualization.Layout == null
protected virtual bool RequestIsForPhysicalFile(string filePath)
<processor patch:before="*[@type='Sitecore.Pipelines.PreprocessRequest.DeviceSimulatorResolver, Sitecore.Kernel']"