Module 03 · AppMeasurement

The s object,
up close.

AppMeasurement is the library that turns variables into network requests. Once you understand this one object, you understand 80% of every Adobe Analytics implementation you will ever read.

Reading50 min
LabEmbedded
DifficultyCore
Pre-reqJavaScript

1 · The anatomy of s

The first time you see an AppMeasurement implementation in the wild, it looks like a wall of boilerplate. Calm down — there are really only three categories of thing inside the s object:

CategoryExamplesYou set these
Configurations.account, s.trackingServer, s.currencyCodeOnce, when the page loads.
Data variabless.pageName, s.eVar1, s.prop1, s.eventsBefore every hit.
Methodss.t(), s.tl(), s.clearVars()You call these.

That's it. Configuration tells Adobe where to send the hit; data variables describe what happened; methods send the hit.

// Configuration (Launch's "Adobe Analytics" extension sets these for you)
s.account = "examplecorpprod";
s.trackingServer = "metrics.example.com";
s.trackingServerSecure = "smetrics.example.com";
s.visitorNamespace = "examplecorp";
s.currencyCode = "USD";

// Data — the page-view payload
s.pageName = "Product Detail: ASTRO-3000";
s.channel = "Telescopes";
s.eVar4 = "ASTRO-3000";        // product SKU
s.prop4 = "telescopes";        // product category
s.events = "prodView";

// Send it
s.t();

That five-line block is a working Adobe Analytics implementation. Everything else in this course is variation on these five lines.

2 · s.t() vs s.tl() — the only two methods that matter

AppMeasurement has many methods. Two of them carry 99% of the load. Master these and you can implement almost anything.

2.1 — s.t(): the page view

s.t() sends a page view hit. It is greedy: it sends every variable currently set on s. Use it when a meaningful new page has loaded.

s.pageName = "Home";
s.channel  = "Home";
s.eVar1    = "logged-in";
s.events   = "event5";
s.t();
// → A page view hit, with pageName, channel, eVar1, events all sent.

Behaviour notes:

  • Increments the page view counter.
  • Sets pageName in the report suite — any subsequent link hits will attribute to it.
  • Clears linkTrackVars and linkTrackEvents after firing.
  • Other variables are not cleared. If you set s.eVar1 = "x" on page A, it will fire again on page B unless you clear it. This is one of the great sources of bugs.

2.2 — s.tl(): the link hit

s.tl() sends a link hit. It is shy: by default it sends almost nothing. You must explicitly whitelist the variables you want sent, using s.linkTrackVars and s.linkTrackEvents.

s.linkTrackVars   = "events,eVar15,prop15";
s.linkTrackEvents = "event10";
s.events = "event10";
s.eVar15 = "newsletter footer";
s.prop15 = "newsletter footer";
s.tl(true, "o", "Newsletter Signup");
//   ↑      ↑   ↑
//   |      |   └── linkName — appears in the Custom Links report
//   |      └────── linkType — 'o' (custom), 'd' (download), 'e' (exit)
//   └───────────── linkObj  — true (or `this`) tells AA not to delay the click

The signature is:

s.tl(linkObj, linkType, linkName, variableOverrides, doneAction);
ArgumentMeaning
linkObjtrue for fire-and-forget. Pass this only if you need the browser to wait (rare).
linkType'o' custom, 'd' download, 'e' exit. The category in reports.
linkNameFree-text label. Appears in the Custom Links / File Downloads / Exit Links report.
variableOverridesObject literal whose values override s's state for this one hit. Rarely used.
doneActionCallback function. Modern code uses Promises instead.
linkTrackVars is the difference

If you set s.eVar15 = "x" and call s.tl(true, "o", "test") without also setting s.linkTrackVars = "eVar15", the eVar will not be on the hit. This catches everyone, including experienced implementers, at least once. Whitelist what you send.

3 · The variable families

3.1 — Standard variables

These have specific reports built around them. Adobe knows what they mean.

VariableHoldsNotes
s.pageNamePage name for the Pages reportSet on every page view. Cap to ~100 chars.
s.channelSite sectionFree-text. Reports as "Site Sections."
s.serverServer / domainOften the hostname.
s.pageType"errorPage" only.Set this to count 404s as not-page-views.
s.campaignTracking code (utm_*)Persists as a marketing-channel touchpoint.
s.eventsComma-separated event list"event1,event3=4.99,purchase"
s.productsProduct stringSee module 05. Multi-product is comma-separated.
s.purchaseIDOrder ID, for de-duping purchase eventsCritical on order confirmation.
s.transactionIDOrder ID for Data Sources / offline joinSame value as purchaseID typically.
s.zip, s.stateCustomer locationUsed in Profile reports.

3.2 — Custom variables

Three families. Memorise these.

FamilyRangePersistenceUsed for
eVar1eVar250 *up to 250Persists across hits per configured rulesConversion attribution
prop1prop75up to 75Hit-level (resets every hit)Traffic patterns, pathing
event1event1000up to 1000Hit-levelCounters and metric values
hier1hier55 onlyHit-levelHierarchical site structure
list1list33 onlyHit-level, delimited multi-valueMulti-select facets, tags

* Standard accounts get 75 eVars. Higher tiers get 100–250. Treat 75 as the practical ceiling.

Module 05 spends 75 minutes on these. For now, you need only this mental model: props describe traffic, eVars accumulate conversion credit, events count things.

3.3 — Hierarchy variables (hier)

A hierarchy variable holds a path: "Home,Telescopes,Astro 3000". Adobe parses the separator and builds a drilldown report. Use them for site taxonomy.

s.hier1 = "Home,Telescopes,Astro 3000";
//        └── separator default: comma

3.4 — List variables (list)

A list variable holds a delimited list of values, each of which Adobe treats as an independent dimension value (so the metric is divided across them, not summed). Three exist: list1, list2, list3.

// "User opened a product that had three categories"
s.list1 = "Telescopes,Astronomy,Optics";
//        └── delimiter is configured in the report suite (default: comma)

Each value gets credit for the page view. Useful for tags, faceted search, or any one-to-many relationship between page and dimension.

3.5 — The products string

The products variable is the strangest piece of AppMeasurement. It packs a product list into a single semicolon-delimited string:

category;name;quantity;price;event-list;eVar-list

telescopes;ASTRO-3000;1;499.00;event3=1.00;eVar5=premium

Multiple products are separated by ,. So a two-product cart looks like:

s.products = "telescopes;ASTRO-3000;1;499.00,accessories;TRIPOD-X;1;79.99";
s.events = "scAdd";

Empty positions are still required:

s.products = ";ASTRO-3000;;;event3=2.50";
//             ↑           ↑↑
//             no category, no qty, no price — just SKU and a merchandising event

We will work through the products string in module 05 with the embedded sandbox. For now, remember its structure: category, name, quantity, price, events, eVars — separated by semicolons; products separated by commas.

4 · The wire format

When you call s.t(), AppMeasurement encodes your variables into a query string and fires an HTTPS request. You will be inspecting this format for the rest of your career, so let's look at it.

https://metrics.example.com/b/ss/examplecorpprod/1/JS-2.20.0/s47213094
  ?ns=examplecorp           <-- visitorNamespace
  &pageName=Product%20Detail
  &ch=Telescopes           <-- channel
  &events=prodView,event3=1
  &v4=ASTRO-3000           <-- eVar4
  &c4=telescopes           <-- prop4
  &h1=Home,Telescopes      <-- hier1
  &l1=Telescopes,Optics    <-- list1
  &products=telescopes;ASTRO-3000;1;499.00
  &g=https%3A%2F%2Fexample.com%2Fastro-3000.html
  &r=https%3A%2F%2Fgoogle.com%2F
  &s=1920x1080             <-- screen resolution
  &mid=01234567890         <-- Marketing Cloud Visitor ID
  &aid=ABCDEF12-34567890   <-- Analytics Visitor ID

The mapping you need to memorise is the short one:

ParamMeans
v1, v2eVar1, eVar2
c1, c2prop1, prop2
h1h5hier1hier5
l1l3list1list3
v0s.campaign
gCurrent URL
rReferrer
pe, pev2Link type, link name (link hits only)
eventsEvent list (uncompressed name)
productsProduct string (uncompressed name)
aidAnalytics ID (legacy visitor cookie)
midMarketing Cloud / ECID
Field test

Open a site you know uses Adobe Analytics. Open DevTools → Network → filter for /b/ss/. Reload. Click the first matching request and read the URL with the table above. You can now decode any AA hit you'll ever encounter. That single skill puts you ahead of most people who claim Adobe Analytics on their CV.

5 · Account & config

These rarely change after initial setup, but knowing them prevents an entire class of "why is no data arriving" mysteries.

// The report suite(s) to write to
s.account = "examplecorpprod";

// Where to send the hit. Adobe issues this URL — get the right one or hits disappear.
s.trackingServer       = "metrics.example.com";
s.trackingServerSecure = "smetrics.example.com";

// First-party cookie domain — Safari ITP demands a CNAME under your own domain
s.visitorNamespace = "examplecorp";

// Currency assumed for all monetary values
s.currencyCode = "USD";

// Character set of variable values
s.charSet = "UTF-8";

// "Outgoing link" determination — anything matching is treated as internal
s.linkInternalFilters = "javascript:,example.com";

Two configuration rules you should treat as commandments:

5.1 Use first-party cookies

Your trackingServer should be a CNAME that points to Adobe but lives under your domain (e.g. metrics.example.com, not examplecorp.sc.omtrdc.net). Otherwise Safari's Intelligent Tracking Prevention will treat your visitor cookie as third-party and effectively expire it every seven days.

5.2 Set linkInternalFilters correctly

This is how Adobe decides which outbound clicks count as "exits." Anything in this comma-list is considered internal; anything else is an exit. Default is your own host — fine for single-domain sites, dangerously wrong for multi-domain estates.

6 · The full method list

MethodUse
s.t()Fire a page view.
s.tl(o, type, name)Fire a link hit.
s.clearVars()Reset most variables to empty. Useful in SPAs (module 07).
s.registerPreTrackCallback(fn)Fire fn just before every hit. Use for last-minute mutation.
s.registerPostTrackCallback(fn)Fire fn after every hit.
s.Util.getQueryParam(name)Read query-string param from the current URL.
s.Util.cookieRead(name)Read a cookie by name.
s.Util.cookieWrite(name, value, days)Write a cookie.

7 · The plugins you will see

For nearly two decades, Adobe shipped a library of helper functions called plugins. They aren't part of AppMeasurement's core — they're extra code you add via Launch. You'll see them everywhere.

PluginDoes
getQueryParamRead a URL query parameter. Used heavily for campaign tracking.
getValOnceReturns a value the first time it sees it, then empty until the cookie expires. De-dupes.
getTimePartingReturns day-of-week / hour-of-day strings.
getPreviousValueStores last hit's value of a variable, returns the previous one.
channelManager / getChannelDetermines marketing channel client-side (alternative to server-side rules).
apl (append-to-list)Appends a value to a delimited list if it isn't already present. Used for list variables.

Adobe has been pushing teams to migrate plugin logic into Launch rules and data elements (where it is visible and version-controlled) rather than relying on hidden plugin code. Default to native Launch logic when starting fresh; respect plugin patterns when inheriting them.

8 · Live sandbox

Time to make this concrete. Below is a working mock of the s object. Edit the code, click RUN, and the simulator decodes the hit you fired — every parameter, exactly the way Adobe's collection server would receive it.

Lab 03.1 — Fire your first hit

Goal: produce a page view hit with pageName, channel, an event, and one eVar. Then add a link hit. Notice which variables travel with each.

code · s_implementation.js
network · captured hits

Notice that the page-view hit carried eVar4 and prop4 automatically, but the link hit only carried events and eVar4 — because that's what linkTrackVars whitelisted. This is the single most important behavioural difference between the two methods.

8.1 — Exercises

Exercise A

Add a second product

Change the page-view to carry a products string with two SKUs. Fire and verify the encoding of the comma between products and the semicolon between fields.

Exercise B

Fire a download link

Send a link hit with type 'd' and name "PDF · Astro 3000 Spec Sheet". Confirm the pe=lnk_d parameter on the wire.

Exercise C

Forget the whitelist

Remove the linkTrackVars line and re-run. Watch the link hit lose all your custom variables. This is the bug you will diagnose dozens of times in your career.

Exercise D

Discover the leak

Set s.eVar1 = "premium" at the top, then fire two page views without clearing. Watch eVar1 fire on both, even though you only meant it for the first. This is the SPA bug from module 07.

Check yourself

You should now be able to: identify any variable from its querystring abbreviation, predict what fires on a t() versus a tl(), build a multi-product products string, and know why linkTrackVars exists. If any of that is unclear, replay the relevant section in the sandbox.