Custom Scripting Language (CSL)

Medallia Agile Research offers a powerful scripting language, called Custom Scripting Language (CSL), that you can use almost anywhere, including in surveys, reports, and emails. You can use it in the subject line or 'from' field or 'to' field of all emails, including those in invitations, reminders, thank-you emails, and notifications. You just the CSL code directly in to your text. You can start by coping and pasting an example and then adjust it to meet your needs.

CSL can be used in a variety of ways, including using variables (placeholders), making calculations, and showing or hiding certain blocks of text.

Variables

Variables in CSL are wrapped with double curly brackets: {{someVariable}}. They are case-insensitive, so {{SomeVariable}} is the same as {{someVariable}}.

Hierarchy

The variables are hierarchical, so you can navigate through them by using dot notation from top level objects working your way down. The following are some examples:

  • Questions in a survey — {{survey.questions}}
  • The text of the first question in survey — {{survey.questions.1.text}}
  • Text of the second answer choice in question 1 — {{survey.questions.1.answerChoices.2.text}}

Survey variables can be found in the variables dropdown in the text editor of your questions, emails, and notifications. See survey interface variables for a list of variables.

In the ReportBuilder, you can find these variables inside the text editor (the Text tab) by clicking the expand button above the text box.

Expand.

Select the Variables dropdown.

Variables dropdown.

Operators

CSL supports special operators that you can implement into your own logic.

In CSL, the operator comes first.

To write 1=1 in CSL is:

{{eq 1 1}}

The 'eq' stands for 'equals'. Behind it is the two arguments to be checked, separated by a space. All CSL operators work this way.

The 'eq' operator expects two arguments. If you need to first do some additional operations, you will need to use parentheses to group the arguments like this:

{{eq (add 1 1) 2}}

When you have parentheses, the contents inside them are done first. So in this case, the 'add' is done first and then the result is evaluated by the 'eq' operator.

The following is an example using an 'if' statement:

{{#if (eq contact.customFields.department 'HR')}} You work in HR! {{/if}}

In the example above, we check if the custom field called 'Department' of the current contact equals 'HR'. If so, we display a text. If not, nothing is shown.

See the following sections for additional information.

Block operators (if, else, each)

You can use block operators to show/hide content depending on your own logic.

OperatorDescription
ifUse the 'if' helper to conditionally display a block. If its argument returns false, null, "", 0 or [], the block will not be visible.
{{#if (and title description)}} This text is only visible if there's a title AND a description. {{/if}}
if + elseSpecify an 'else' block to be displayed if the first condition is not met.
{{#if contact}} <h1>{{contact.firstName}} {{contact.lastName}}</h1> {{else}} <h1>Unknown respondent</h1> {{/if}}
else ifCombine multiple 'if' blocks using 'else if'. Agile Research will evaluate each 'if' in order until it finds one that is true or it reaches the 'else'. Once one of the 'if' blocks is true, the others are ignored even if they are true too.
{{#if contact}} <h1>{{contact.firstName}} {{contact.lastName}}</h1> {{else if respondent.questions.yourName}} <h1>{{respondent.questions.yourName}}</h1> {{else}} <h1>Unknown respondent</h1> {{/if}}
unlessUse the 'unless' helper as the inverse of the 'if' helper. Its content will be displayed if the condition is not met (if the value is either false, null, "", 0 or [])
{{#unless response}} <h3 class="warning">Warning: There's no response!</h3> {{/unless}}
eachIterate over a list using the built-in 'each' helper. Inside the block, you can use this to reference the element being iterated over or immediately use underlying properties.
<ul> {{#each report.elements}} <li>{{title}}</li> {{/each}} </ul>
each + elseTogether with an 'each' operator, you can optionally provide an 'else' section which will display only when the list is empty.
{{#each report.elements}} <h2>{{title}}</h2> {{else}} <p>No elements in this list!</p> {{/each}}
commentsUse a comment block to add an internal remark or temporarily prevent some CSL from executing.
{{!-- Everything inside this block will not be shown or executed --}}

Logical operators (and, or, equals, greater than)

Use logical operators to check and compare variables. These operators are most often used inside block operators like 'if' or in display logic.

A CSL condition is a statement that is either true or false.

The following is a simple example that will return true:

{{eq 1 1}}

The 'eq' stands for 'equals'. In CSL, the operator is always placed first. The other two items are what is being compared ,so it says '1 is equal to 1'. This is true.

The following is an example that will return false:

{{eq 1 2}}
OperatorDescription
eq Returns true if two arguments are equal.
eq 1 1
neReturn true if two arguments are not equal.
ne 1 2
ltReturns true if the first argument is less than the second.
lt 9 12
gtReturns true if the first argument is greater than the second.
gt 15 12
leReturns true if the first argument is less than or equal to the second.
le 12 12
geReturns true if the first argument is greater than or equal to the second.
ge 12 12
containsReturns true if the text of the first argument contains the second argument.
contains respondent.questions.comment "unhappy"
andReturns true if all arguments are true.
and (eq 1 1) (lt 2 3)
orReturns true if any of the arguments are true.
or (eq 1 1) (eq 1 3)
notReverses the result. Returns true if the inner condition is false and false if the inner condition is true. For example, check if a respondent is a contact. This will return true if they are not a contact.
not contact

Math operators (add, subtract, round)

Use math operators to work with numbers. You can perform calculations or control how numbers are presented.

OperatorDescription
addAdd two or more numbers.
10 + 5 = {{add 10 5}} Result: 10 + 5 = 15
subtractSubtracy two or more numbers.
10 - 5 = {{subtract 10 5}} Result: 10 - 5 = 5
multipleMultiple two or more numbers.
10 * 5 = {{multiply 10 5}} Result: 10 * 5 = 50
divideDivide two or more numbers.
10 / 5 = {{divide 10 5}} Result: 10 / 5 = 2
averageAverage two or more numbers.
The average of the numbers 1,2,3,4 = {{average 1 2 3 4}} Result: (1+2+3+4) / 4 = 2.5
sqrtCalculate the square root of a number.
The square root of 25 is {{sqrt 25}} Result: The square root of 25 is 5
powCalculate the first argument raised to the power of the second argument.
Three to the power of two is {{pow 3 2}} Result: Three to the power of two is 9
modCalculate the remainder after dividing the first argument by the second.
5 % 4 = {{mod 5 4}} Result: 5 % 4 = 1
absReturn the absolute value of a number.
The absolute value of -10 is {{abs -10}} Result: The absolute value of -10 is 10
roundRound a number to the amount of digits specified. If no digits are specified, the number is rounded to 0 digits.
The first rounded value is {{round 25.9999}}, the second is {{round 12.123456 2}} Result: The first rounded value is 26. The second is 12.12
floorRound a number downward to its nearest whole number.
{{floor 25.9999}} Result: 25
ceilingRound a number upward to the next whole number.
{{ceiling 25.13}} Result: 26
randomGenerate a random number between the numbers specified.
A random number between 5 and 10 is {{random 5 10}} Result: A random number between 5 and 10 is e.g. 8
random + excludeGenerate a random number, excluding certain values. You can add as many excluded values as you like.
A random number between 5 and 10, excluding 7 and 8 is {{random 5 10 exclude="7,8"}} Result: A random number between 5 and 10, excluding 7 and 8 is e.g. 9
countGet a count of the number of items in a list/array.
There are {{count report.elements}} elements in this report Result: There are 3 elements in this report
kFormat a number to the K notation.
{{k 12468}} Result: 12K
decExplicitly choose the decimal separator.
{{dec 12.3 ","}} Result: 12,3
expReturns the constant e = 2.71828… raised to the power of a given number.
{{exp 5}}
Result: 148.4132 (e raised to the power 5 equals 148.4132)
logIf you pass two arguments, the log operator returns the logarithm of a number to the base you specify.
{{log 30 5}}
number = 30 and base = 5
Result: 2.1133 (5 raised to the power 2.1133 equals 30)

If you pass one argument, the log operator returns the natural logarithm of a number.

{{log 25}}
Result: 3.2189 (the constant e=2.71828 raised to the power 3.2189 equals 25)

Date operators (add, diff, format)

Use date operators to display or manipulate dates and times.

OperatorDescription
currentDateReturn the current date and time in the date format and timezone of the survey owner.
Today is {{currentDate}}. Result: Today is 08/17/2000 4:14 PM.
.isoAdd to any date to get the date in ISO format. This format is machine readable. Use for prefilling and postfilling.
Today is {{currentDate.iso}}. Result: Today is 2000-08-17 16:14.
.utcAdd to any date to get the date in ISO 8601 format in the UTC timezone. This format is machine readable. Use when sending a date to a database or API.
Today is {{currentDate.utc}}. Result: Today is 2000-08-17T14:14Z.
.dateAdd to any date to get only get the date portion of a date excluding the time.
Today is {{currentDate.date}}. Result: Today is 08/17/2000.
.timeAdd to any date to get only get the time portion of a date excluding the date.
The time now is {{currentDate.time}}. Result: The time now is 4:14 PM.
.relativeAdd to any date to get the relative date, described in words.
You were born {{contact.dateOfBirth.relative}}. Result: You were born 30 years ago.
Tip: Use .relative.styled to get the relative date with the original date as a tooltip.
.year

.month

.month.text

.day

.dayOfWeek

.dayOfWeek.text

.hour

...

Add to any date to get only that portion of the date.
You were born in {{contact.dateOfBirth.year}}. Result: You were born in 1970.
regionalSettings.timezoneOffsetHoursGet the time difference between the survey owner's local timezone and Coordinated Universal Time (UTC). This is based on the user profile of the survey owner.
My UTC offset is {{regionalSettings.timezoneOffsetHours}} hours. Result: My UTC offset is 4 hours.
dateFormatDisplay a date using a specified format.
Your birthdate: {{dateFormat contact.dateOfBirth "MMM d yy"}} Result: Your birthdate: Feb 12 87

Some examples of the formats you can use are as follows:

i: 2000-08-17 I: 2000-08-17 16:32:32 a: 2000-08-17 16:32 d: 08/17/2000 D: Thursday, August 17, 2000 f: Thursday, August 17, 2000 16:32 F: Thursday, August 17, 2000 16:32:32 g: 08/17/2000 16:32 G: 08/17/2000 16:32:32 m: August 17 r: Thu, 17 Aug 2000 23:32:32 GMT s: 2000-08-17T16:32:32 t: 16:32 T: 16:32:32 u: 2000-08-17 23:32:32Z U: Thursday, August 17, 2000 23:32:32 y: August, 2000 dddd, MMMM dd yyyy: Thursday, August 17 2000 dddd, MMMM dd: Thursday, August 17 M/yy: 8/00 dd-MM-yy: 17-08-00
dateAddAdd a certain timespan to a date. Specify the date, number of units to add (subtracting can be done by using a negative value), and the unit. The unit can be one of the following: year, month, day, hour, minute, or second.
We'll reply before {{dateFormat (dateAdd respondent.dateResponded 3 "day") "D"}}. Result: We'll reply before Thursday, August 17, 2000.
Note: The date is always returend in the ISO 8601 format. Use dateFormat if you want to render it in a stylized way.
dateDiffCalculate the difference between two dates. Specify the start and end date along with the unit. The unit can be year, month, day, hour, minute, or second.
We've invited you {{dateDiff contact.dateInvited currentDate "day"}} days ago. Result: We've invited you 3 days ago.
dateinTimeZoneShow a date in a specific time zone.
{{dateInTimeZone respondent.dateResponded "Mountain Standard Time"}} Result: 2020-12-09 10:05

To show the date in a format that is easy to read, also use a dateFormat operator:

{{dateFormat (dateInTimeZone respondent.dateResponded "Mountain Standard Time") "g"}} Result: 12/9/2020 10:05 AM (depending on your date and time settings)

All supported time zones can be found in list of time zones.

Text operators (replace, trim split)

Use text operators to change how text is rendered.

OperatorDescription
upperCaseConvert the text to uppercase letters.
{{upperCase "Some text"}} Result: SOME TEXT
lowerCaseConvert the text to lowercase letters.
{{lowerCase "Some TEXT"}} Result: some text
trimRemove whitespace at the start and end of text.
{{trim " Some text "}} Result: Some text
replace Replace a sequence of characters in a string with another set of characters. This operator accepts three terms: The text to be searched, the text to find, and the replacement text: {{replace textToSearch textToFind replaceWith}}
{{replace "I love blue." "blue" "red"}} Result: I love red.

This operator is case insensitive and will replace all occurrences of the search term.

splitSplit text based on a character and returns one part. This operator accepts three terms: The text to split, the character to split the text by (delimiter), index of the part to return: {{split textToSplit characterToSplitOn index}}

The following is an example of a comma-delimited string for which a second item will be extracted:

{{split "Blue,Red,Green" "," 2}} Result: Red.
leftExtract the first characters of a piece of text.
{{left "Some text" 2}} Result: So
rightExtract the last characters of a piece of text.
{{right "Some text" 3}} Result: ext
substringExtract characters from a piece of text. This operator accepts three arguments: the text, the index of the first character, and the number of characters to extract. Omit the last argument to extract the rest of the text.
{{substring "Some text" 3}} / {{substring "Some text" 3 5}} Result: me text / me te
.unformattedRemove formatting from text.
{{survey.questions.myDataLabel.text.unformatted}} Result: Example text with a part in italics.

Place this at the end of a variable to strip the HTML formatting and display everything as plain text.

urlEncodeMake text suitable for URLs.
{{urlEncode "Some text?"}} Result: Some%20text%3F

This should be used when using variables in URLs that may contain spaces, slashes, or other special characters. Numbers do not need to be URL encoded. For instance, use this operator in a branch to an external URL or in a link placed on the thank-you page. You can also add '.urlEncoded' to the end of a variable. For example:

{{survey.questions.myDataLabel.text.urlEncoded}}
jsonEncodeMake text suitable for JSON.
{{jsonEncode 'Test "123"'}} Result: Test \"123\"

This should be used when creating JSON, and the text might contain backslashes, double quotes ,or other special characters. You can also add '.jsonEncoded' to the end of a variable. For example:

{{survey.questions.myDataLabel.text.jsonEncoded}}
hashConvert text to a 64-character has code.
{{hash "Some text"}} Result: 4C2E9E6DA31A64C70623619C449A040968CDBEA85945BF384FA30ED2D5D24FA3

This operator generates a 64-character hash using the SHA-256 hashing algorithm. If you pass multiple values, they will be joined as one string and then hashed. This way, you can add a so-called salt value to make your hashes harder to guess. Combine with postfilling. For example:

{{hash respondent.questions.name respondent.questions.birthdate "some salt value"}}

Visuals (icon, modal, tooltip, QR code)

Use modals and popovers to display extra information when the respondent clicks a link. Use modals for longer text or images and use popovers for small bits of information or to explain a word.

Note: These operators are only supported in the survey interface and reports.
OperatorDescription
iconDisplay a small icon. Specify an identifier from 

Font Awesome

.
{{icon "far fa-star"}}
modalDisplay a link to open a modal window.
Click {{modal "here" "This text is inside the modal window."}} for more info. Result: Click here for more info. Result inside the modal window: This text is inside the modal window.

Add an icon as follows:

Click {{modal "here" "This text is inside the modal window." icon="fas fa-info-circle"}}!

If your text inside the modal window is long, you can also use the #modal variant:

{{#modal "click here"}} This text can be longer and contain markup, quotes and variables. {{/modal}}
tooltipDisplay a tooltip or text balloon when moving your mouse over something.
This is a {{tooltip "NPS" "Net Promotor Score"}} question. Result: This is a NPS question. Result inside tooltip: Net Promotor Score>
Note: Since there is no mouse on mobile, it is activated by clicking.
By default, tooltips are displayed above the link. You can override this position by specifying left, right, or bottom.
{{tooltip "Click here" "Displayed on the right" position="right"}}

Adding an icon is also possible. Add the FontAwesome class of the icon that you want to use as the last parameter.

{{tooltip "Click here" "Some text" position="top" icon="fas fa-info-circle"}}

If your text inside the tooltip is long, you can also use the #tooltip variant:

{{#tooltip "Click here"}} This text can be longer and contain markup, quotes and variables. {{/tooltip}}
popoverThe same as a tooltip but only activated by clicking, not by moving your mouse over it.
This is a {{popover "NPS" "Net Promotor Score"}} question. Result: This is a NPS question. Result inside popover: Net Promotor Score
lightboxShow a small version of an image. When it is clicked on, a large version of the image is displayed by filling the screen and dimming out the rest of the page.
{{#lightbox}}Agile Research logo{{/lightbox}}

Add {{#lightbox}} before and {{/lightbox}} after the image to make it clickable. When clicked, the image is shown full screen. Optionally, add multiple images inside the same lightbox to create a gallery.

You can also show an image inside a lightbox without using an image, but using text instead:

{{lightbox "Agile Research logo" "https://www.agileresearch.com/wp-content/ uploads/2016/03/AgileResearch-logo.png"}}
qrcodeShow a QR code of a URL or text snippet. You can optionally provide the size in pixels. The max size is 270.
{{qrCode "https://www.agileresearch.com/" 100}}

QR code.

You can also use variables. For instance, if you have a coupon code in a contact custom field called 'coupon', use the following:

{{qrCode contact.customFields.coupon 100}}
See Tooltips, popovers, and modal windows for more information.

Temporary variables

Use custom temporary variables to split big functions into smaller parts. These variables are not stored anywhere, they're only temporarily available within the same page.

OperatorDescription
setSave a temporary value. You need to specify a name and the value.
{{set "mySum" (add 1 2)}}

To save a large piece of text, you can also use the #set variant:

{{#set "myText"}} This sample text can be longer and contain markup, quotes and variables. {{/set}}

You can combine text by passing multiple values, as follows:

{{set "greeting" "Hello " contact.firstName "!"}}
Note: No result is returned at this time. Use the function below to retrieve this variable.
get
{{get "mySum"}} Result: 3

Retrieve a temporary value using the name you specified with the 'set' operator.

Lookup operators

Look up information from a contact list as if it was a database and return that information to surveys, notifications, and reports.

OperatorDescription
contactListLookupMany users want to look something up in a database. This function lets you use contact lists as a sort of database. For instance, an employee enters their employee number and their department, level, and manager are retrieved from a contact list. This function has four terms:
  1. Contact list id to search
  2. Field to search
  3. Value to search for (case insensitive)
  4. Field to return
{{contactListLookup 1234 "customFields.1" "Emp4574" "email"}} Result: first.last@yourcompany.com

You can optionally specify an extra term 'contains' to look for a partial match instead of an exact match. For example, "ACME" would also match "ACME Corporation".

{{contactListLookup 1234 "customFields.2" "ACME" "email" "contains"}} Result: info@acme-corporation.com

This can go further than contacts (people). Think more abstractly and you can look up anything. For instance, place a list of stores in a contact list and when someone enters their city, you return the address of the location in that city or someone selects their store and the email address of the store manager is placed in the 'to' field for a notification of an unhappy customer.

queryStringLookupExtract a querystring parameter from a URL.
{{queryStringLookup "https://example.com?code=123" "code"}}
Result: 123
USStateToAbbreviationGet the abbreviation for a given US state.
{{USStateToAbbreviation "Texas"}} Result: TX
USStateFromAbbreviationGet the name of a US state from its abbreviation.
{{USStateFromAbbreviation "TX"}} Result: Texas

Combinations

You can combine all these operators to create more advanced logic.  The most common example is combining 'and', 'or', and 'not'. To do that, think in terms of true or false. Each item is evaluated and then compared using the operators.

For example:

{{eq 1 1}}

This is true. 1 equals 1.

Using 'and':

{{and (eq 1 1) (eq 2 2)}}

This is true. 1 equals 1 and 2 equals 2.

Using 'or':

{{or (eq 1 2) (eq 2 2)}}

This is true. 1 does not equal 1, but 2 does equal 2. 'or' is true if any of the terms are true.

Using 'not':

{{not ( or(eq 1 3) (eq 2 2))}}

This is false. 1 does not equal 3 but 2 does equal 2. the 'not' reverses the result. Simplified, the code can then be seen as:

{{not (or false true)}}

The or is true since one of the terms is true, so you get the following:

{{not (true)}}

'Not' makes the true become false:

{{false}}

Examples

You can combine all these operators to create more advanced logic. See Survey CSL snippets to see snippets of CSL code that you can use in your surveys. If you do not find code that does exactly what you want, you may be able to modify existing examples to fit your needs.