HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket


Describes the routing concept used for displaying catalog content in Optimizely Customized Commerce.

The Optimizely Customized Commerce routing system extends the Optimizely Content Management System (CMS) Routing system to expose catalog content like products, variants, and categories using individual URLs. The data sent to the client browser is compiled by a matching rendering template. Categories have their own URL and can have their own rendering template, for instance to display a product listing. See Customized Commerce rendering templates.

Catalog content URLs have two forms:

  • Hierarchical URL. In the form domain/language/catalog/category/product, following the catalog's structure. For example, mysite.com/en/wine/accessories/corkscrew.
  • Simple address/SEO URL. A single segment uniquely identifying content and its language. For example, mysite.com/professional-corkscrew-en.aspx.

The SEO URL field has been part of the catalog information since previous versions of Customized Commerce. The new routing works the same as the CMS "Simple address" concept. Hence, you may see both terms used.

Register routes

Register the catalog partial router in an EPiServer to enable routing to catalog content.Framework.IInitializableModule using the CatalogRouteHelper.

using System.Web.Routing;
    using EPiServer.Framework;
    using EPiServer.Commerce.Routing;
    using EPiServer.Framework.Initialization;
    namespace CodeSamples.EPiServer.Commerce.Catalog
        public class RegisterRoutingModuleSample : IInitializableModule
            public void Initialize(InitializationEngine context)
            private static void MapRoutes(RouteCollection routes)
                CatalogRouteHelper.MapDefaultHierarchialRouter(routes, true);
            public void Uninitialize(InitializationEngine context) { /*uninitialize*/}
            public void Preload(string[] parameters) { }

Outgoing routes

Outgoing routes are used when rendering links in the template. For example, using the Html.ContentLink helper (ASP.NET MVC), the EPiServer.Web.Routing.UrlResolver class or links are added to an Xhtml property by an editor. Customized Commerce routes also register an outgoing route, which is determined by the flag passed to CatalogRouteHelper in the initialization:

  • CatalogRouteHelper.MapDefaultHierarchialRouter(routes, false) uses hierarchical links.
  • CatalogRouteHelper.MapDefaultHierarchialRouter(routes, true) uses the SEO URL in links.

Work with hierarchical URLs

Hierarchical URLs are constructed using the Name in URL property of each content instance in the hierarchy, leading to the requested content. The first segment is the catalog, followed by categories and subcategories down to the target category, product, variant, and so on. To determine the language, either a language segment (for example, "en/") is prepended, or the configured site host mapping is used; see Globalization scenarios.

The Name in URL property value is automatically generated from the Name when new content is created. Because only certain characters are valid in a URL and because the Name in URL needs to be unique in the catalog, it may not match Name. A unique value is added to the end of the Name in URL if other content in the catalog has the same Name in URL as the new content Name. You can edit Name in URL to any valid value - it does not have to resemble Name.



If your site uses Optimizely CMS version 10.6 or higher, your developer can define a custom character set to be used with the Name in URL and the SEO URL fields. The custom set can support characters outside RFC 1738. For more information, see Internationalized Resource Identifiers (IRIs) and URL segment and SEO URI.

Work with SEO URLs

SEO URLs are stored in the SEO URL property and should be unique across all catalogs and languages, which is why only one segment is needed to identify the requested content. It also means that the URL is unaffected by moving the product in the catalog tree, or changing the Name in address of a content somewhere above in the hierarchy.

The SEO URL property value is automatically generated from the Name when creating content. For additional language versions, the language code is appended to make the SEO URL unique. Because only certain characters are valid in a URL and because the SEO URL needs to be unique across catalogs, it may not match the Name. By default, an .aspx extension is used, but the SEO URL can be edited to any valid value. It does not have to resemble Name or include an extension.

Change the default generation of SEO URL, and name in url

The UniqueSeoGenerator class is called when an SEO URL or uri segment (name in url) is created. To override this logic, inherit from UniqueSeoGenerator and override GenerateSeoUri and/or GenerateUriSegment. The custom unique SEO generator must be registered in an initialization module.

public class ExntedUniqueSeoGenerator : UniqueSeoGenerator
        protected override string UriExtension
                return ".html";
        public override string GenerateSeoUri(string name, string languageCode, bool includeRandomToken)
            return includeRandomToken
              ? String.Format("{0}_{1}_{2}{3}", CommerceHelper.CleanUrlField(name), languageCode, GetRandomToken(), UriExtension)
              : String.Format("{0}_{1}{2}", CommerceHelper.CleanUrlField(name), languageCode, UriExtension);
        public override string GenerateUriSegment(string name, bool includeRandomToken)
            return includeRandomToken
              ? String.Format("{0}_{1}", UrlSegment.GetUrlFriendlySegment(name), GetRandomToken())
              : UrlSegment.GetUrlFriendlySegment(name);
        protected override string GetRandomToken()
            var chars = "abcdefghijklmnopqrstuvwzyz1234567890";
            var random = new Random();
            var result = new string(Enumerable.Repeat(chars, 8) .Select(s => s[random.Next(s.Length)]) .ToArray());
            return result;

Related blog post: