Displaying Data with Templates


ISML stands for Internet Store Markup Language. These files have the .isml extension and they define how data, tags, and page markup are transformed into HTML that is sent to the browser, using Cascading Style Sheets (CSS) for page layout and styling.

Salesforce Commerce Cloud Digital uses templates to generate dynamic HTML-based web pages for responses sent back to the client.

First, let’s get you started by understanding what you can do with ISML, then we will take a short tour on how ISML templates are organized on our site and finally how do we do to avoid hardcoding text strings that become visible to the user.

Pdict Variable

pdict keys Alternatives

pdict is a hashmap on which key, object pairs can be loaded on the frontend. However, there are some built-in pdict keys (variables) that provide access to the most commonly used objects, such as session and request.
This means that any data that you send from the backend to the frontend, doesn’t matter if using res.render or res.setViewData, on the frontend, they will be loaded inside the pdict variable.

ISML expressions provide access to data by using dot notation. This example accesses a property of the Product object in the pipeline dictionary: ${pdict.varName}

JavaScript controllers can use alternatives to pdict keys. The table on the left shows some of them.

In other words, controllers have access to request, response, session, customer objects just like you have on the frontend using pdict. You just need to use the valid import or require statements.

ISML Tags and Expressions

ISML tags are Commerce Cloud proprietary extensions to HTML that developers use inside ISML templates. ISML tags and expressions can only be written in ISML templates.

ISML tags always start with is, e.g. <isprint> and describe, together with regular HTML, how dynamic data will be embedded and formatted on the page.

Depending on their tasks, ISML tags can be divided into the following groups as shown in the table below.

Group Tags Purpose

HTTP- related


Sets cookies in the browser
Sets the MIME type
Redirects browsers to specific URLs
Define status codes

Flow Control

Evaluates a condition
<iselse> <iselseif>
Specifying alternative logic when an <isif> condition does not evaluate to true
Creates a loop statement
Jumps to the next iteration in a loop statement
Terminates loops

Variable - related

Creates a variable
Removes a variable


Includes the contents of one template on the current template
Declares a custom tag
Includes the output of a controller or pipeline on the current page


Allows Commerce Cloud Digital Script execution inside templates


Enhances the HTML <select> tag


Formats and encodes strings for output
Creates a content slot
Creates a content asset


Caches a page
Adds comments
Reuses a template for page layout
Replaces content inside a decorator template

Active Data

Allows collection of active data from pages with a tag
Collects category context from a page for active data collection
Collects specific object impressions/views dynamically

ISML Expressions

ISML Expressions are based on the Digital Script language. Since Digital Script implements the ECMAScript standard, access to variables, methods, and objects is the same as using JavaScript.

ISML expressions are embedded inside ${…} to enable the ISML processor to interpret the expression prior to executing an ISML tag or the rest of the page.

ISML expressions can also access Digital Script classes and methods. Two packages are available implicitly in ISML, so classes do not need to be fully qualified:

  • TopLevel package: session.getCustomer()
  • dw.web package: URLUtils.url(), URLUtils.webRoot()


TopLevel package has a class named global which is implied so doesn’t need to be in the prefix. Other access to classes and methods must be fully qualified: ${dw.system.Site.getCurrent().getName()}

Examples of ISML expressions:

  • ${TopLevel.global.session.getCustomer().getProfile().getLastName()}
  • Since TopLevel package and global class are implicit, the previous code is equivalent to the following code: ${session.getCustomer().getProfile().getLastName()}
  • You can replace the get method with properties. So the previous code example is equivalent to the following code:
    • ${session.customer.profile.lastName}
    • ${pdict.CurrentSession.customer.profile.lastName}
    • ${pdict.CurrentCustomer.profile.lastName}
    • ${dw.system.Site.getCurrent().getName()}
    • ${dw.system.Site.current.name}

ISML expressions also allow complex arithmetical, boolean, and string operations: ${pdict.myProduct.getLongDescription() != null}


In this section we will cover the most frequently used tags: <isprint><isset><isinclude> <isdecorate><isloop> and the conditional tags <isif><iselseif>, and <iselse>.

Although there are some ISML tags that do not need a corresponding closing </> tag (i.e.: the <isslot> tag), it is best practice to always use a closing tag.

Printing variables within the page

Type Description
Prints money with currency symbol e.g. $3,333.00
Prints money without the symbol e.g. 3,333.00
Prints the value with two decimal places e.g. 3,455.35
Rounds of and prints only the integer portion e.g. 3,455
Prints date in the long format like Jul 24, 2016
Prints date in the short format like 07/24/2016
Prints strings containing HTML

The <isprint> tag can print the formatted output of a variable or an expression to the browser. In order to do so, it uses built-in styles or formatters. You can see the documentation for formatters. Examples using isprint with styles:

  • <isprint value=”${myMoney}” style=”MONEY_LONG>/>
  • <isprint value=”${myMoney}” style=”MONEY_SHORT>/>
  • <isprint value=”${myNumber}” style=”DECIMAL>/>
  • <isprint value=”${myNumber}” style=”INTEGER>/>
  • <isprint value=”${new Date()}” style=”DATE_LONG>/>
  • <isprint value=”${new Date()}” style=”DATE_SHORT>/>
  • <isprint value=”${myString}” encoding=”off>/>

Creating and Accessing Variables

You can create and access your own custom variables in an ISML template by using the <isset> tag.
When using the <isset> tag, name and value are required attributes that must be assigned. The default scope is the session, so you must be careful to qualify your variables accordingly if you do not want them.

Example: <isset name = “<name>” value = “<expression>” scope = “session”|”request”|”page”>

Value attribute:The value attribute from the isset tag can be a hardcoded string or number, or an ISML expression accessing another variable or object.

Value Type Example
value="hardcoded text"

Scope Attribute: An <isset> variable’s scope attribute refers to its accessibility levels, such as session, request, and page. It is important to understand the scopes of a variable and which objects can access that variable at each level. Listed are the scopes from the widest to narrowest access.

Scope Definition
Available through the whole customer session, even across multiple requests. Any variable added to the session scope becomes a custom attribute of the session object. Since it is not a standard attribute it must be accessed with the session.custom qualifier: ${session.custom.myVar}
variables are available for the current internal Salesforce B2C Commerce request. The request variable isn't available for multiple requests, so it isn't available after an interaction continue node.
Available only for a specific ISML page, and its locally included pages. Their scope is limited to the current template and any locally included templates. They are accessed without a prefix: ${pageVar}

Here are some examples of using isset tag and retrieving the variables back from the scope session scope:

  • <isset name=”x” value=”12343″ scope=”session”/>
  • <isset name=”x” value=”${12343}” scope=”session”/>
  • <iscomment> Session is implied here </iscomment>
  • <isset name=”x” value=”12343″ />
  • Retrieving from session${session.custom.x} | ${pdict.CurrentSession.custom.x}
  • Request Scope${request.custom.x} | ${pdict.CurrentRequest.custom.x}
  • Page Scope${x}


More information about <isset> tag can be found here.

Reusing Code in Templates

Reusable code saves time in both code creation and updates. It also reduces errors and helps to ensure a consistent look and feel.

You can use the following tags to reuse code in ISML templates:

Tag Description

Embed an ISML template inside an invoking template. There are two types:

Local Include - include the code of one ISML template inside of another while generating the page (All variables from the including template are available in the included template, including page variables.)

Remote Include - include the output of another controller inside of an ISML template.

  • This is used primarily for partial page caching.
  • pdict and page variables from invoking template are not available in the included template.
  • The only variables available to a remotely included javaScript controller are session variables.
  • Includes from another server are not supported.
Decorate the enclosed content with the contents of the specified (decorator) template. A decorator is an ISML template that has HTML, CSS, and the overall page design.
Define your own ISML tags which can be used like any standard tags.
Invokes a remote include.

Local include syntax: <isinclude template=”[directory/]templatename”/> (You do not need to add the .isml extension when including a template)

Remote Include syntax: <isinclude url=”${URLUtils.https(‘controller_url’)}”/>

Here some examples:

  • <isinclude template=”extras/calendar”/> (Local include)
  • <isinclude url=”${URLUtils.url(‘ConsentTracking-Check’)}”/> (Remote include)

In this example, the dw.web.URLUtils.url() method builds a site-specific URL for the ConsentTracking-Check controller. Never hard-code a controller URL since it would contain a specific server in it. Use methods from URLUtils instead.

Passing URL parameters: To pass parameters to your controller, you use the following syntax:
<isinclude url=”${URLUtils.https(‘controller_url’, <parameterId_1>, <parameterValue_1>, .. <parameterId_n>, <parameterValue_n>)”/>


Finally, you could also implement a remote include, via the <iscomponent> tag. It also supports passing multiple attributes.

     pipeline = <string> | <expression> [locale = <string> | <expression> ]
     [any number of additional arbitrarily named parameters]

In practice, this tag is not being used anywhere in SFRA. We are using <isinclude> instead.This tag is similar to a remote include. However, it uses pipeline-related attributes to specify the content generating target and allows for arbitrary attributes.

Technically, the <iscomponent/> tag performs the same function as a remote include. The use of remote includes, however, might not be obvious. The tag, with its direct association to a pipeline, makes its purpose obvious. It’s intended to embed reusable functionality, encapsulated in a pipeline, into another template. It also lets the embedded component have a different caching policy than the included page.

Reusing Page Layouts

One very cool feature that ISML offers us is the possibility to create page layouts and reuse those layouts on any pages we want so that we avoid creating pages from scratch every single time.

Also, it makes maintenance much simpler because if we need to fix anything on the page, including SCSS or javascript imports, we just need to fix the page layout being used and it will be reflected to all pages using it.

To these page layouts, we give the name decorator template and make use of them we use the <isdecorate> tag.

These files are kept in a specific folder app_storefront_base\cartridge\templates\default\common\layout

The decorator template uses <isreplace/> to identify where to include the decorated content. The following example shows a decorator and the area where the code is being replaced by whatever template that uses the decorator.

A typical use case is to decorate the content body with a header and footer. See the app_storefront_base\cartridge\templates\default\common\layout\page.isml file for example:

Typically, the decorator template only uses one tag, <isreplace/>. However, you can use multiple tags. If the decorator template uses multiple <isreplace/> tags, the content to be decorated will be included for each <isreplace/> tag.

See the example below where we have the homepage using our a decorator:
<isdecorate template=”common/layout/page” />

Conditional Statements

Most programming languages use the keywords if, else if, and else for conditional statements. Commerce Cloud Digital uses similar keywords but adds the is prefix to the beginning of the syntax:

<isif condition=”${ISML expression evaluated}”>
     Do something here if true.
<iselseif condition=”${check another condition}”>
     Do something if this one is true.
     If none of the above conditions are true, do this.

To use a conditional statement in an ISML template:

  1. Determine the location on your ISML page where you want to write your conditional statement.
  2. Open your conditional statement with the <isif condition=””> tag. Example:
<isif> tag example usage


With the <isloop> tag you can loop through the elements of a specified collection or array.

For example, you can list data such as: categories, products, shipping, and payment methods. You can even nest <isloop> statements (put one inside another). You can use the following supporting tags with <isloop>:

  • Use the <isbreak> tag within a loop to terminate a loop unconditionally. If used in a nested loop, it terminates only the inner loop.
  • Use <isnext> to jump forward within a loop to the next list element of an iterator. This tag affects only the iterator of the inner loop. If an iterator has already reached its last element, or an iterator is empty when an <isnext> is processed, the loop is terminated instantly.

The full syntax for using the <isloop> tag is:

     iterator|items = “<expression>” [ alias|var = “<var name>” ]
     [ status = “<var name>” ] [ begin = “<expression>” ] [ end = “<expression>” ]
     [ step = “<expression>” ]>
          … do something in the loop using <var_name>…

The attributes have the following usage:

Attribute Description
items (iterator)
The expression returning an object to iterate over. Attributes iterator and items can be used interchangeably.
var (alias)
Name of the variable referencing the object in the iterative collection referenced in the current iteration.
Name of the variable name referencing loop status object. The loop status is used to query information such as the counter or whether it is the first item.
The expression specifying a begin index for the loop. If the begin is greater than 0, the skips the first x items and starts looping at the begin index. If begin is smaller than 0, the is skipped.
The expression specifying an end index (inclusive). If the end is smaller than begin, the is skipped.
The expression specifying the step used to increase the index. If the step is smaller than 1, 1 is used as the step value.

For example, if the <isloop> tag declares a status=”loopstate” variable, then it is possible to determine the first time the loop executes by using: <isif condition=”${loopstate.first}”>. Another example of <isloop> tag is:

For the status variable, the following properties are accessible:

Attribute Description
The number of iterations, starting with 1.
The current index into the set of items, while iterating.
True, if this is the first item while iterating (count == 1).
True, if this is the last item while iterating.
True, if the count is an odd value.
True, if the count is an even value.

Creating custom tags with <ismodule>

There are three key ISML files required for creating and using a custom tag:

  • The ISML file which sets the values of any attributes of the custom tag. (modules.isml)
  • In the template attribute, you specify the ISML file which defines what happens when the attributes are passed. See the contents of app_storefront_base\ cartridge \templates \default \components \content \contentAsset.isml
  • And this is how you Invoke the custom tag inside an ISML template pageFooter.isml

Resource Bundles

In storefront code, we should avoid hard-coding text strings. Titles, labels, messages, buttons and field names should all be externalized by using resource bundles (a.k.a. properties files).

If you do not want to duplicate ISML templates in order to create locale-specific templates, you can use resource bundles to keep your template generic and reusable.

A resource bundle is a file with a .properties extension that contains the hardcoded strings to be used in ISML templates. In SFRA bundles are loosely named by the functional area where the strings are used, but you can use any file name and organization you want.

By default, they are located always at <cartridge_name>\cartridge\templates\resources

The resource bundles contain key=value pairs, where the key might be compound (key.subkey) and the value, is a hard-coded string that uses Java MessageFormat syntax to implement parameter replacement.

Strings from the bundles are accessible to all ISML templates through 2 methods from the API:

  • Resource.msg: Use it when you only need to retrieve a value
  • Resource.msgf: Use it when you need to retrieve a value passing a parameter will replace a placeholder (e.g {0}) in there

More information can be found here.

See some examples on how to define these key=value pairs and how to use them.

Did you notice that some have values like {0} and {1}? These are placeholders that will be dinamically replaced by parameters you pass when using Resource.msgf.

After the 3rd parameter, you can pass any number of values you want as a parameter and inside the resource bundle, they will be identified by {}, starting from 0 and incrementing by 1 for each extra parameter you pass.

That’s the biggest difference between both methods. One only retrieved hard-coded strings that don’t accept parameters, the other accepts parameters.

Use the Resource.msgf to replace these placeholder.

Programming Possibilities Await: Click to Transform Your Coding Journey!


You might be wondering: Ok, but what do we do when we need the site to support multiple languages or when the site must look different for different countries/languages?

For templates, you will create a folder with the country_language code and replicate the subfolders and files from the default folder.

For Resource Bundles, you will append the country_language code to the name of the file and add the translations to each corresponding file:

Practical Exercises

How to be a Certified Salesforce Commerce Cloud Developer for FREE

Unlock a FREE PDF with SFCC B2C Certification questions from our Udemy Course. Join our newsletter!
Check your email, you’ll receive a copy in a few seconds. If you don’t see it, please check your spam folder.

Do you like cookies? 🍪 We use cookies to ensure you get the best experience on our website. Learn more.