Summary Learn how to write links in emails that can be personalized and support tracking.
Digital Marketing Solutions Adobe Campaign 5.11, 6.0, 6.1, 6.11, 7
Audience Advanced users, Administrators

If you have questions about this article or about any other Adobe Campaign topic, ask the Community.


The links in email content that contain personalization need specific syntax to be tracked. 

Using JavaScript in email content (HTML or Text) allows you to generate and send dynamic content to the recipients, with two limitations:

  • The script cannot access the database directly (SQL function and API functions are not available)
  • Adobe Campaign must be able to detect URLs so that links can be tracked (purpose of this document)

Personalization and tracking process overview

For tracking detection, Adobe Campaign embeds Tidy to parse the HTML source and detect the pattern. It lists all the URLs of the content so that they can be tracked individually. Adobe Campaign uses Tidy again to replace the URL ( with a URL pointing to the Adobe Campaign redirection server.

For example, in the initial content:<%=escapeUrl(recipient.lastName)%> is replaced for one particular recipient with:,71ffa3,71ffa8&p1=Bare


  • "h" means HTML content (or "t" for text content).
  • 617791 is the message ID / broadLog ID (hexadecimal).
  • 71ffa3 is the NmsDelivery ID (hexadecimal).
  • 71ffa8 is the NmsTrackingUrl ID (hexadecimal).
  • p1, p2, and so on, are all the parameters to substitute in the URL.

Detecting tracking URLs

Example of non-detection

<%= getURL("") %> works and sends the actual content of the web page via email to the recipients. But none of the links are tracked. The reason for this is that the MTA executes "<%=getURL(..." for each email before sending. It can be different for each recipient, so Adobe Campaign cannot know the URLs for tracking and assign them a tag ID.

When the page to download is the same for all recipients, the best practice is to do the following:

<%@ include url="" %>

In that case, the page is downloaded during the analysis, before the tracking detection. It allows Adobe Campaign to discover the links, assign a tag ID, and track them.

Recommended Pattern

After processing <%@ instructions, the URL to be tracked has the following syntax:

<a href="<%=escapeUrl(>&param3=<%=escapeUrl(>">

Warnings on http://<%=myURL%> pattern

The <a href="http://<%=myURL%>"> syntax is not recommended because:

  • Tidy can incorrectly patch some of the links, which can happen randomly. The typical symptom is a piece of HTML that is visible in the email proofs but not in the preview.
  • Escaping of the URL is problematic, some characters in the URL can cause problems.
  • You cannot have a parameter named ID conflicting with parameter in the redirection URL.
  • Interest of tracking is then limited to statistics on the delivery, as Adobe Campaign indifferently tracks all possible values of "myURL".

<%@ instructions

These pre-processing instructions are not JavaScript, this syntax is specific to Adobe Campaign.

They only apply in the context of delivery content. It is the only way to script the URL of an email and still have it tracked (besides URL parameters). They can be seen as an automatic copy/paste applied during the delivery analysis before detecting the links to track.

There are three types of instructions:

  • "include": mainly to factorize some cod in options, personalization blocks, external files, or pages
  • "value": to give access to fields of the delivery, delivery variables and custom objects loaded in the delivery
  • "foreach": to loop an array loaded as a custom object.

They can be tested directly from the delivery wizard. They apply in the content preview and when you click the tracking button to see the list of the URLs.

<%@ include

The following examples are among the most commonly used:

  • Including the mirror page link: <%@ include view="MirrorPage" %>
  • Mirror page URL: "View as a <a href="<%@ include view='MirrorPageUrl' %>" _label="Mirror Page" _type="mirrorPage">web page"
  • Out-of-the-box unsubscription url: <%@ include option='NmsServer_URL' %>/webApp/unsub?id=<%= escapeUrl(recipient.cryptedId)%>
  • Other examples:
    • <%@ include file='' %>
    • <%@ include file='file:///X:/france/service/test.html' %>
    • <%@ include option='NmsServer_URL' %>

Use the personalization button in the delivery wizard to get the correct syntax.


<%@ value

This instruction gives access to parameters of the delivery that are constant for all recipients.


<%@ value object="myObject" xpath="@myField" index="1" %>


  • "object": name of the object (example: delivery, provider, and so on).
  • "xpath": xpath of the field.
  • "index" (optional): if "object" is an array (for extra script objects), item index in the array (Starts at 0).

Object can be:

  • "delivery": for the current delivery (see details and restrictions in the subsection below).
  • "provider": for the current delivery provider/routing (nms:externalAccount).
  • An extra script object: if an object is loaded in the context through: Properties > Personalization > Add objects in the execution context.
  • Item of the foreach loop: see Foreach section below.

"delivery" object

For email personalization, the delivery object is accessible in two ways:

  • In JavaScript. For example: <%= delivery.myField %>. In the JavaScript object delivery custom fields are not supported. They work in the preview, but not in the MTA because the MTA can only access the out-of-the-box delivery schema.
  • Through <%@ value object="delivery" pre-processing

For the <%@ value object="delivery" xpath="@myCustomField" %> instruction, there is another limitation for deliveries sent via mid-sourcing. The custom field @myCustomField must be added to the nms:delivery schema on both marketing and mid-sourcing platforms.

Note: for delivery parameters/variables, use the following syntax (using the delivery object):

<%@ value object="delivery" xpath="variables/var[@name='myVar']/@stringValue" %>

<%@ value in a JavaScript section

To allow using <%@ value in script sections, two special objects are replaced with <% and %>:

  • <%@ value object='startScript' %>
  • <%@ value object='endScript' %>

For example:

<%@ value object='startScript' %> var iMode = <%@ value object="delivery" xpath="@deliveryMode" %> if(iMode == 1) { ... } else { ... } <%@ value object='endScript' %> is expanded in something like <% var iMode = 1 if(iMode == 1) { ... } else { ... } %>.

<%@ foreach

This instruction allows iteration on an array of objects loaded in the delivery to track individual links related to the objects.


<%@ foreach object="myObject" xpath="myLink" index="3" item="myItem" %> <%@ end %>


  • "object": name of the object to start from, typically an extra script object, but it can be a delivery.
  • "xpath" (optional): xpath of the collection to loop on. Default is ".", meaning that object is the array to loop on.
  • "index" (optional): if xpath is not "." and object is an array itself, item index of object (starts at 0).
  • "item" (optional): name of a new object accessible with <%@ value inside the foreach loop. Default with the link name in the schema.


In the delivery properties/personalization, load an array of articles and a relation table between recipient and articles.

Displaying links to these articles can be done simply with a Javascript as follows:

   for(var i=0; i<recipient.rcpArticle.length; i++ )
     %><a href="<%=recipient.rcpArticle[i].article.@id%>">article</a><%

With that solution, the links to all the articles are tracked without distinction. You can know that a recipient has clicked an article link, but you cannot know on which article.

The solution is to:

  1. Pre-load all the possible articles in an extra script array of the delivery - articleList[] - which means there must be a finite number of possible articles.
  2. Write a JavaScript function at the beginning of the content.
<%@ value object='startScript' %>
 function displayArticle(articleId)
    <%@ foreach object="articleList" item="article" %>
      if( articleId == <% value object="article" xpath="@id" %> ) 
        <%@ value object='endScript' %>
          <a href="<%@ value object="article" xpath="@id" %>">article</a>
        <%@ value object='startScript' %>
    <%@ end @%>
 <%@ value object='endScript' %>

3. Display the article by calling the function.

   for(var i=0; i<recipient.rcpArticle.length; i++ )

Esta obra está licenciada sob uma licença não adaptada da Creative Commons Attribution-Noncommercial-Share Alike 3.0  As publicações do Twitter™ e do Facebook não são cobertas pelos termos do Creative Commons.

Avisos legais   |   Política de privacidade online