at.js Frequently Asked Questions

Answers to frequently asked questions about at.js.

This section contains the following information:

What are the advantages of using at.js versus mbox.js?

Although at.js replaces mbox.js, mbox.js will continue to be supported. However, for most people, at.js provides advantages over mbox.js.

Among other benefits, at.js improves page-load times for web implementations, improves security, and provides better implementation options for single-page applications.

The following diagram illustrates page-load performance using mbox.js versus at.js.

As illustrated above, using mbox.js, page content does not begin to load until after the Target call is complete. Using at.js, page content begins loading when the Target call is initiated and does not wait until the call is complete.

Why does it seem like I see slower response times after upgrading from a previous version of at.js to version 1.0.0?

at.js version 1.0.0 and later fires all the requests in parallel. Previous versions execute the requests sequentially, meaning the requests are put in a queue and Target waits for first request to complete before moving on to the next request.

The way previous versions of at.js execute requests is susceptible to the so-called "head of line blocking." In at.js 1.0.0 and later, Target switched to parallel request execution.

If you check the network tab waterfall for at.js 0.9.1, for example, you'll see that next Target request doesn't start until the previous one has finished. This is not the case with at.js 1.0.0 and later where all the request basically start at the same time.

From a response-time perspective, mathematically, this can be summed like this

  • at.js 0.9.1: Response time of all Target requests = sum of requests response time
  • at.js 1.0.0 and later: Response time of all Target requests = maximum of requests response time

As you can see, at.js 1.0.0 will complete the requests faster. In addition, at.js requests are asynchronous, so Target doesn't block page rendering. Even if requests take seconds to complete, you will still see the rendered page, only some portions of the page will be blanked out until Target gets a response from the Target edge.

What is the impact of at.js on page-load times?

For more information, see Understanding the Target JavaScript Libraries.

Can I load the Target library asynchronously?

The at.js library should be loaded synchronously as best practice; however, you can load it asynchronously as an experimental option.

The at.js 1.0.0 release makes it possible to load the Target library asynchronously.

To load at.js asynchronously:

  • The recommended approach is via a tag manager such as Adobe Dynamic Tag Manager (DTM) or the new Adobe Launch. See the Adobe Dynamic Tag Manager documentation for more information.

  • You can also load at.js asynchronously by adding the async attribute to the script tag that loads at.js. You should use something like this:

    <script src="<URL to at.js>" async></script>
  • You can also load at.js asynchronously using this code:

    var script = document.createElement('script');
    script.async = true;
    script.src = "<URL to at.js>";

Loading at.js asynchronously is a great way to avoid blocking the browser from rendering; however, this technique can lead to flicker on the web page.

You can avoid flicker by using a pre-hiding snippet that will be visible after the relevant HTML elements are personalized by Target. We recommend using a tag manager such as Adobe DTM or the new Adobe Launch to add the pre-hiding snippet. The snippet must be added before loading at.js.

The pre-hiding code snippet is as follows:

;(function(win, doc, style, timeout) {
  var STYLE_ID = 'at-body-style';

  function getParent() {
    return doc.getElementsByTagName('head')[0];

  function addStyle(parent, id, def) {
    if (!parent) {

    var style = doc.createElement('style'); = id;
    style.innerHTML = def;

  function removeStyle(parent, id) {
    if (!parent) {

    var style = doc.getElementById(id);

    if (!style) {


  addStyle(getParent(), STYLE_ID, style);
  setTimeout(function() {
    removeStyle(getParent(), STYLE_ID);
  }, timeout);
}(window, document, "body {opacity: 0 !important}", 3000));

By default the snippet pre-hides the whole HTML BODY. In some cases, you may only want to pre-hide certain HTML elements and not the entire page. You can achieve that by customizing the style parameter. It can be replaced with something that pre-hides only particular regions of the page.

For example, you have two regions identified by IDs container-1 and container-2, then the style can be replaced with the following:

#container-1, #container-2 {opacity: 0 !important}

Instead of default:

body {opacity: 0 !important}

Is at.js compatible with the Adobe Experience Manager integration (AEM)?

Adobe Experience Manager 6.2 with FP-11577 (or later) now supports at.js implementations with its Adobe Target Cloud Services integration. For more information, see Feature Packs and Integrating with Adobe Target in the Adobe Experience Manager 6.2 documentation.

How can I prevent page-load flicker using at.js?

Target provides several ways to prevent page-load flicker. For more information, see How at.js Manages Flicker.

What is the file size of at.js?

The at.js file is approximately 109 KB when downloaded. However, because most servers automatically compress files to make file sizes smaller, at.js is approximately 34 KB when compressed (using GZIP or another method) on your server and loaded as users visit your website. The compression settings on the server where you installed at.js determine its actual compressed size.

Why is at.js bigger than mbox.js?

at.js implementations use a single library (at.js), while mbox.js implementations actually use two libraries (mbox.js and target.js). So a fairer comparison is at.js versus mbox.js and target.js. Comparing the gzipped sizes of the two versions, at.js version 1.2 is 34 KB and mbox.js version 63 is 26.2 KB.

at.js is larger because it does a lot more DOM parsing compared to mbox.js. This is required because at.js gets "raw" data in the JSON response and has to make sense of it. mbox.js uses document.write() and all the parsing is done by the browser.

Despite the larger file size, our testing indicates that pages load faster with at.js versus mbox.js. Additionally, at.js is superior from a security perspective because it doesn't load additional files dynamically or use document.write.

Does at.js have jQuery in it? Can I remove this part of at.js because I already have jQuery on my website?

at.js currently uses parts of jQuery and thus you will see the MIT license notification at the top of at.js. jQuery is not exposed and it doesn't interfere with the jQuery library you already have on your page, which might be a different version. Removal of the jQuery code within at.js is not supported.

Does at.js support Safari and cross domain set to x-only?

No, if cross domain is set to x-only and Safari has third-party cookies disabled, then both mbox.js and at.js will set a disabled cookie and no mbox requests will be executed for that particular client's domain.

To support Safari visitors, a better X-Domain would be “disabled” (sets only a first-party cookie) or “enabled” (sets only a first-party cookie on Safari, while setting first- and third-party cookies on other browsers).

Can I run at.js and mbox.js side by side?

Not on the same page. However, while implementing and testing at.js, you can run at.js on some pages and mbox.js on other pages until you've completely validated at.js.

Can I use the Target Visual Experience Composer in my single-page applications?

The Visual Experience Composer (VEC) was designed for static web content and server-side-driven web applications. Depending on your SPA architecture, you may or may not be successful using the VEC. Each SPA framework and application is different and may have different results. Expect to need front-end developer support to create activities in single-page applications.

Your SPA should load in the VEC so you can see if it will work for simple content changes in your application. If you have trouble loading your SPA in the VEC, open a Client Care ticket. You should also be able to use the "Browse&Navigate" feature to get to the right state of your application to begin making edits, as well as target the Activity URL to hash fragments and mbox parameters to deliver the activity content to the right mbox.

The main challenges are timing:

  • VEC offer replaces content before the SPA has fully updated. The updated SPA content then replaces the VEC content.
  • VEC offer looks for SPA content that is not yet on the page. After several tries the offer will give up. The SPA content then loads.
  • SPA content loads and is visible before the VEC offer is returned and can replace it, resulting in flicker.

An implementation strategy that initiates mbox calls as close as possible to dynamic content can help. Please see the SPA Implementations page.

Can I use the Adobe Marketing Cloud Debugger with at.js implementations?

No, at.js implementations are not compatible with the Marketing Cloud Debugger. All mbox calls with at.js use XHR requests, which are not exposed by the debugger. Instead, we recommend that you use mboxTrace for debugging purposes. You can also use your browser's Developer Tools to inspect the Network requests, filtering to "mbox" to isolate mbox calls.

Can I use special characters in mbox names with at.js?

Special characters, including ampersands (&), cannot be used in mbox names with at.js.

If you have migrated from mbox.js to at.js and you have mbox names that contain special characters, as a workaround, you can rename the affected mboxes.

Why are my mboxes not firing on my web pages?

Target customers sometimes use cloud-based instances with Target for testing or simple proof-of-concept purposes. These domains, and many others, are part of the Public Suffix List.

Modern browsers won't save cookies if you are using these domains unless you customize the cookieDomain setting using targetGlobalSettings(). For more information, see Using Cloud-Based Instances with Target.

Can IP addresses be used as the cookie domain when using at.js?

Yes, if you are using at.js version 1.2 or later. We strongly recommend that you keep current with the latest version, however.

Note: The following examples are not necessary if you are using at.js version 1.2 or later.

Depending on how you use targetGlobalSettings, you might need to make additional modifications to the code after downloading at.js. For example, if you needed slightly different settings for your Target implementations on various websites and were unable to define these settings dynamically using custom JavaScript, make these customizations manually after downloading the file and before uploading to the respective website.

The following examples let you use the targetGlobalSettings() at.js function to insert a code snippet to support IP addresses:

This example is for a single IP address:

if (window.location.hostname === '123.456.78.9') {
    window.targetGlobalSettings = window.targetGlobalSettings || {};
    window.targetGlobalSettings.cookieDomain = window.location.hostname;

This example is for a range of IP addresses:

if (/^123\.456\.78\..*/g.test(window.location.hostname)) {
    window.targetGlobalSettings = window.targetGlobalSettings || {};
    window.targetGlobalSettings.cookieDomain = window.location.hostname;

Why do I see warning messages, such as "actions with missing selectors"?

These message are not related to at.js functionality. The at.js library tries to report anything that can't be found in the DOM.

The following are possible root causes if you see this warning message:

  • The page structure that activity is running on has been changed. If you reopen the activity in the Visual Experience Composer (VEC), you should get a warning message. You should update the activity so that all the necessary elements can be found.

  • The underlying page is part of a Single Page Application (SPA) or the page contains elements that appear farther down the page and the at.js "selector polling mechanism" cannot find those elements. Increasing the selectorsPollingTimeout might help. For more information, see targetGlobalSettings().

  • Any click-tracking metric tries to add itself to every page, regardless of the URL on which the metric was set up. Although harmless, this situation makes many of these messages display. Recent versions of at.js try to suppress these messages, but many customers are still on older versions of at.js or on mbox.js.

    For best results, please download and use the latest version of at.js. For more information, see at.js Version Details and Download at.js.