← Back to list

Adobe Stack Daily #002 — mboxTrace Isn’t Gone in Web SDK. You’re Just Looking in the Wrong Place.

Three debugging tools, one real production risk nobody talks about, and why your Recs algorithms quietly degrade after migration.

Pranav Mandlik · 2026-04-29 01:56 · 10 claps · 9.0 min read
#adobe-target #web-sdk #adobe-experience-platform #target-recommendations #martech
Open on Medium ↗
Wiki topics: SOC · Sociology & Politics AIM · AI in Marketing 💻 · Programming 🔧 · Data Engineering

Adobe Stack Daily #002 — mboxTrace Isn’t Gone in Web SDK. You’re Just Looking in the Wrong Place.

Three debugging tools, one real production risk nobody talks about, and why your Recs algorithms quietly degrade after migration.

Three Debugging Paths for Target Recs in Web SDK

What this diagram shows: The full debugging surface after migrating to Web SDK. mboxTrace via data.__adobe.target still works — it's just under documented. Assurance is the primary tool most teams skip. Edge Trace fills the structural gaps. All three sit on top of the same Edge Network layer. The bottom section shows the behavioral pipeline split — the silent production risk no one talks about during migration planning.

The migration looked clean. Web SDK firing, Target decisions coming through, Recs rendering on the page. Everything seemed fine.

Then a recommendation stopped making sense — wrong category, wrong algorithm, items that should’ve been excluded weren’t. You opened the browser, looked for the Recs Box, and got nothing. Just network calls and a JSON blob you’d never had to read before.

That’s not a bug. That’s the debugging model changing completely under you.

But here’s the part nobody documents clearly: mboxTrace is not gone. It still works in Web SDK. You just trigger it differently. More on that in a moment — but first, you need to understand why the surface changed at all.

What mboxTrace Actually Gave You

With at.js, mboxTrace was a debug layer bolted directly onto the Target response. Add the token to the URL, refresh, and Target appended a full diagnostic payload to every mbox response. The Recs Box was in there.

That Recs Box gave you:

  • Which algorithm and criteria set ran — criteria ID, algorithm type (collaborative filtering, item-based, popularity-based, user-based)
  • How many entities were in the catalog at query time
  • Which items were returned before filtering
  • Exactly why items were excluded — inventory rules, profile attribute mismatch, max price filter, recent purchase exclusion, all of it with per-entity reason strings
  • The final ranked list before rendering

Verbose, sometimes enormous, completely readable. One JSON object. You could grep it, share it, paste it into a Slack thread.

Web SDK changed where that data lives. Not whether it exists.

Why the Surface Changed

With at.js, the browser called Target’s delivery API directly. The mboxTrace payload came from Target’s backend, packaged into that same direct response.

Web SDK calls the Edge Network. Target runs as one internal service inside the Edge. The browser never talks to Target directly. Every request hits /ee/v2/interact on edge.adobedc.net, the Edge orchestrates which services run, and Target's output comes back wrapped in the Edge response structure.

mboxTrace as a URL parameter hitting Target’s delivery endpoint doesn’t apply in the same way. But the underlying Target trace capability still exists. The Edge just mediates it now.

Debug Tool #1 — mboxTrace Still Works. Here’s How.

This is the part that isn’t documented clearly anywhere.

Authentication first. mboxTrace in Web SDK still requires your browser to be authenticated against the Adobe Experience Cloud org that owns the Target instance. Open Experience Cloud (experience.adobe.com) and confirm you're logged in before proceeding. Without this, the parameter is silently ignored — no error, no trace, nothing.

The right parameter value. Pass "mboxTrace": "json" — not "windows". The windows value opens a popup, which is the at.js browser UI experience. In Web SDK you're reading the trace through AEP Debugger's Edge Trace, so you need "json" to get a machine-readable payload embedded in the Edge response.

alloy("sendEvent", {
  renderDecisions: true,
  data: {
    __adobe: {
      target: {
        "mboxTrace": "json",
        "entity.id": "SKU-1234",
        "entity.categoryId": "electronics"
      }
    }
  }
}).then(result => {
  console.log(result.propositions);
});

Where to find the output. Open AEP Debugger → Edge tab → click Connect → reload the page → find your interact request → expand com.adobe.target in Edge Path Trace. The Target trace payload is embedded in the Target service's response node. It's not as clean as the old Recs Box UI — it's raw JSON — but the data is the same: criteria ID, entities evaluated, filters applied, exclusion reasons per entity, final ranked output.

This is the closest equivalent to the original mboxTrace workflow. Use it when you need per-entity exclusion detail.

Debug Tool #2 — Adobe Experience Platform Assurance

Most teams don’t use this. It’s the right primary tool for Web SDK debugging.

Access it via the AEP UI: experience.adobe.com → left nav → Data Collection → Assurance. Create a new session, give it a name, and enter the base URL of the page you want to debug. Assurance generates a deep link — a version of your page URL with session parameters appended. Open that link fresh in your browser. Alloy detects the session parameters, establishes a WebSocket connection to Assurance, and from that point every event is streamed into your session view.

What Assurance shows that AEP Debugger doesn’t:

  • Activity name — not just a numeric ID you have to look up in Target UI
  • Experience name — which variation qualified
  • The full proposition payload for Recs, including the entity list in a readable format
  • Proposition ID — useful when troubleshooting A4T stitching
  • A clean event timeline with labels — you can see exactly which sendEvent triggered which Target decision

The failure mode to know about. Assurance sometimes shows a Target event fired and a proposition returned — but the page isn’t rendering the Recs. When this happens, the problem is not in delivery. It’s client-side rendering. The offer came back correctly; something in your subscribeRulesetItems handler or applyPropositions call is failing silently. Assurance tells you the boundary: if the proposition is in Assurance, the delivery layer is clean. Look at your rendering code.

For day-to-day Recs debugging — wrong items, wrong criteria, activity not qualifying — start with Assurance. Move to mboxTrace only when you need exclusion detail per entity.

Debug Tool #3 — Edge Trace in AEP Debugger

Right tool for understanding scope routing and request/response structure. Not the first place to look for a Recs content problem, but necessary for certain failure modes.

Enable it: AEP Debugger → Edge tab → click Connect. The Debugger injects a trace session token into subsequent requests. Reload the page.

Find the right event: The events list shows every request Alloy made. You’re looking for type interact. If multiple fire on load, cross-reference the timestamp with your browser's network tab.

Navigate to Target data: Expand the interact event → Edge Path Tracecom.adobe.target. That's the service node. Not com.adobe.target.recommendations — just com.adobe.target. Recs data is inside it.

What the Recs payload looks like:

{
  "type": "personalization:decisions",
  "payload": [
    {
      "id": "AT:eyJhY...",
      "scope": "recs-homepage",
      "scopeDetails": {
        "activity": { "id": "123456" },
        "experience": { "id": "0" },
        "strategies": [
          {
            "algorithmID": "popularity",
            "trafficType": "0"
          }
        ]
      },
      "items": [
        {
          "schema": "https://ns.adobe.com/personalization/html-content-item",
          "data": {
            "content": "[{\"entity.id\":\"SKU-001\",\"entity.name\":\"Blue Running Shoe\",...}]"
          }
        }
      ]
    }
  ]
}

scopeDetails.strategies[].algorithmID is where the algorithm type lives. "popularity" is the value for popularity-based algorithms (Most Viewed, Top Sellers, etc.). For collaborative filtering algorithms — People Who Viewed This Viewed That, People Who Bought This Bought That — the value will be a different identifier. Cross-reference what you see in the trace against the algorithm type shown in your Target Recs criteria configuration in the Target UI. If they don't match, your behavioral signal pipeline is the likely cause.

The entity list is in items[].data.content as a JSON-encoded string. Parse it to read it. Exclusion reasons are not in this payload — for those, use mboxTrace.

The scope problem you’ll hit. The scope in the proposition must match what your sendEvent is requesting. Form-based Recs activities: scope equals the mbox name, direct mapping. VEC-based activities: scope is __view__ for page load, or the SPA view name for single-page views. If you filter result.propositions by p.scope === "recs-homepage" and get nothing, your Recs activity is VEC-based. Check p.scope === "__view__" instead.

To verify what scopes your request is actually sending: check query.personalization.decisionScopes in the Edge request payload in AEP Debugger.

The Real Production Risk: Behavioral Data Migration

This is the failure mode that shows up weeks after go-live, produces no errors, and takes engineers days to diagnose.

How it worked in at.js (1.x):

// at.js 1.x — behavioral signals sent directly to Target
// at.js 2.x uses adobe.target.sendNotifications() instead
adobe.target.trackEvent({
  mbox: "orderConfirmPage",
  params: {
    "orderId": "ORD-9999",
    "productPurchasedId": "SKU-001,SKU-002",
    "orderTotal": "149.00"
  }
});

Target’s collaborative filtering (CF) and user-based (UB) algorithms trained on those signals directly — product views, cart adds, purchases. The algorithm knew what each user did and built associations from it.

How it works in Web SDK — use both XDM and data.__adobe.target:

XDM commerce events alone are not guaranteed to reach Target Recs behavioral signal processing. They do only if your datastream is explicitly configured to map productListItems[].SKU to entity.id for Target — which is not the default. The most reliable approach is dual-path: send XDM for Analytics and AEP, and send entity parameters via data.__adobe.target for Target.

// Purchase event — behavioral signal for Recs algorithms
alloy("sendEvent", {
  xdm: {
    eventType: "commerce.purchases",
    commerce: {
      purchases: { value: 1 },
      order: {
        purchaseID: "ORD-9999",
        priceTotal: 149.00
      }
    },
    productListItems: [
      { SKU: "SKU-001" },
      { SKU: "SKU-002" }
    ]
  },
  data: {
    __adobe: {
      target: {
        "orderId": "ORD-9999",
        "productPurchasedId": "SKU-001,SKU-002",
        "orderTotal": "149.00"
      }
    }
  }
});

// Product view — behavioral signal for CF and UB algorithms
alloy("sendEvent", {
  xdm: {
    eventType: "commerce.productViews",
    commerce: { productViews: { value: 1 } },
    productListItems: [{ SKU: "SKU-001", name: "Blue Running Shoe" }]
  },
  data: {
    __adobe: {
      target: {
        "entity.id": "SKU-001",
        "entity.categoryId": "shoes"
      }
    }
  }
});

If you’re relying on XDM-only behavioral tracking: go to Data Collection → Datastreams → your datastream → Adobe Target configuration. Verify that your entity field mappings are explicitly configured. If there are no field mappings defined for entity.id, entity.categoryId, and similar parameters, Target is not receiving the entity context it needs from XDM events alone. Add the dual-path approach above while you sort out the datastream mapping.

Why the degradation is delayed — the lookback window. CF and UB algorithms don’t train on real-time data. They operate on a rolling behavioral lookback window — typically 14 to 30 days depending on the algorithm type. While at.js is still running, that window stays full of good behavioral data, and your algorithms keep serving accurate recommendations.

The moment you remove at.js without a functioning Web SDK behavioral pipeline, the window starts draining. For the first week or two, recommendations still look right — the algorithm is drawing on historical data. Then, as old data ages out of the window and no new data replaces it, the algorithm starts falling back toward popularity-based outputs. By the time the full lookback window has turned over with no new behavioral signals, you’re effectively serving the same popular items to everyone.

No errors. No monitoring alerts. Just gradually worse recommendations, and an investigation that starts two weeks after go-live when someone finally asks why the “Recommended for You” section looks the same for every user.

How to catch it before it’s a problem: After migration and before removing at.js, verify that product view and purchase events are firing in Web SDK AND reaching Target. Open Assurance and confirm you see commerce.productViews and commerce.purchases events with entity parameters in the payload. Then check that the Target node in Assurance shows the behavioral events being processed — not just the Recs delivery. If you see delivery working but no behavioral event acknowledgment from Target, your signal pipeline is broken and your algorithms will degrade on a 14–30 day delay.

Edge Cases That Will Catch You

Recs not appearing at all — activity is active, scope looks right.

Check data.__adobe.target in the Alloy request payload in AEP Debugger. If you're not passing entity.id and entity.categoryId for context-based criteria, algorithms that depend on current item context won't execute. In at.js these were mbox parameters. In Web SDK they go in data.__adobe.target — they don't come from XDM automatically.

alloy("sendEvent", {
  renderDecisions: true,
  data: {
    __adobe: {
      target: {
        "entity.id": "SKU-1234",
        "entity.categoryId": "electronics"
      }
    }
  }
});

Multi-workspace implementations — Recs silently not qualifying.

If your Target instance uses at_property tokens to scope activities to specific workspaces, that token must be passed in data.__adobe.target. Activities in non-default workspaces will not qualify without it. No error. No fallback. Just no Recs.

data: {
  __adobe: {
    target: {
      "at_property": "your-workspace-token",
      "entity.id": "SKU-1234",
      "entity.categoryId": "electronics"
    }
  }
}

Entity IDs from behavioral events not matching the catalog.

If the entity.id in your behavioral tracking event doesn't exactly match the entity.id in your catalog feed, Target registers the behavioral event but can't link it to the product. The algorithm sees activity but builds no associations from it. Check case sensitivity — catalog feeds are often generated from backend systems with uppercase SKUs, while the front end sends lowercase. Silent mismatch, no error, algorithm trains on garbage associations.

───────────────────

Adobe Stack Daily — Problem #002 of 40

One real Adobe stack problem, every day for 40days — AEP, AJO, Adobe Target, Data Collection, and CJA. No theory. Problems from real enterprise implementations, written down so you don’t spend 4 hours finding the answer.

🔗 Previous: Adobe Stack Daily #001 — You Can’t Store MM-DD-YYYY in AEP. Here’s What’s Actually Happening. 🔗 Follow me on Medium to get the next one.


메타데이터
post_id
e8e6fea1daff
slug
adobe-stack-daily-002-mboxtrace-isnt-gone-in-web-sdk-you-re-just-looking-in-the-wrong-place-e8e6fea1daff
url
https://medium.com/@pranavmandlik8/adobe-stack-daily-002-mboxtrace-isnt-gone-in-web-sdk-you-re-just-looking-in-the-wrong-place-e8e6fea1daff
canonical_url
https://medium.com/@pranavmandlik8/adobe-stack-daily-002-mboxtrace-isnt-gone-in-web-sdk-you-re-just-looking-in-the-wrong-place-e8e6fea1daff
author_url
https://medium.com/@pranavmandlik8
status
ok
fetched_at
2026-07-09 09:29:37