Skip to content

fix(site): send analytics events in the WebSDK's XDM shape - #2815

Merged
yonib05 merged 4 commits into
strands-agents:mainfrom
yonib05:fix/analytics-xdm-event-shape
Jun 16, 2026
Merged

yonib05 merged 4 commits into
strands-agents:mainfrom
yonib05:fix/analytics-xdm-event-shape

Conversation

@yonib05

@yonib05 yonib05 commented Jun 16, 2026

Copy link
Copy Markdown
Member

Description

The custom analytics events dispatched from site/src/components/Analytics.astro were never reaching Adobe. Two independent bugs in the dispatch layer caused every custom event to be silently dropped:

  1. Wrong listener name. The AWS WebSDK listens on a single event name, custom-awsm-acs-event-listener. Our code dispatched to two names that the SDK does not listen on: custom-awsm-acs-analytics-event-listener and custom-awsm-acs-search-event-listener.
  2. Wrong payload shape. The SDK reads event content from the XDM namespace detail.xdm._aws.<namespace> and validates it before sending. Our code wrapped content in detail.data.<namespace>, so the validators rejected and dropped each event.

Because of this, the page-view / scroll / link-click data visible in Adobe actually came from the SDK's own auto-instrumentation (auto page views, scroll detection, clickCollectionEnabled link tracking) — not from this code. Internal search has no SDK auto-equivalent, which is why search reporting showed zero and surfaced the bug.

I verified the correct contract against the upstream packages AWSMarketingAdobeWebSDKClientSideLibs and AWSMarketingAdobeWebSDKHelpers (the helpers/*-event.ts builders and the listener constant), and confirmed it against the production wsdk.js bundle served from d0.m.awsstatic.com (it listens only on custom-awsm-acs-event-listener and reads _aws / searchOperations / customCTAClick).

What changed

  • Dispatch through the single correct listener custom-awsm-acs-event-listener, wrapping content as detail.xdm._aws.<namespace> (search, custom CTA, and scroll all updated).
  • Remove the invalid page-view event. It used pageInteraction with name: 'pageView', but the only valid PageInteractionName values are impression and scroll; the SDK auto-fires the standard web.webpagedetails.pageViews itself. The dead siteSection / hierarchy fields it carried had no destination variable on the report suite and are removed.
  • Make the code-copy hierarchy label base-path aware (anchors on the docs path segment) so a deploy base path like /pr-xxxx/ does not leak into the label.
  • Now that custom events actually land, extend click tracking to cover existing interactive UI that was previously untracked or only captured generically:
    • Language toggle (Python/TypeScript) → lang-toggle:<lang>
    • GitHub dropdown linksgithub-menu:<label>
    • Sidebar group expandsidebar-expand:<group>
    • Content tabs (npm/yarn, OS; language tabs are excluded because AutoSyncTabs hides them) → tab:<label>
    • Landing CTAshome-cta:<text-or-href>
    • Blog cards and post navblog-card:<href>, blog-nav:<label>
    • Code-copy broadened to landing CodeBlock and install-command buttons → code-copy:<hierarchy|install:cmd>

Related Issues

Type of Change

Bug fix

Testing

Verified end to end against the deployed PR preview build (https://d3ehv1nix5p99z.cloudfront.net/pr-cms-2815/) using browser automation. Attached listeners for both the correct event name and the two old (buggy) names, then triggered real clicks and inspected each dispatched event.

Result — every custom event now fires on custom-awsm-acs-event-listener with the detail.xdm._aws.* shape; zero events on the old listener names, and no detail.data payloads:

Action eventType xdm._aws content
Language toggle web.awsm.customCTAClick pageInteraction.click = { name: "lang-toggle:Python", type: "click" }
GitHub dropdown link web.awsm.customCTAClick pageInteraction.click = { name: "github-menu:Python SDK", type: "linkClick" }
Install copy button web.awsm.customCTAClick pageInteraction.click = { name: "code-copy:install:pip install strands-agents", type: "customClick" }
Docs code copy web.awsm.customCTAClick `pageInteraction.click = { name: "code-copy:user-guide
Sidebar group expand web.awsm.customCTAClick pageInteraction.click = { name: "sidebar-expand:Tools", type: "click" }

Preview testing also surfaced the base-path bug: on the /pr-cms-2815/ preview the code-copy label was originally code-copy:pr-cms-2815|docs|user-guide|.... After the base-path-aware fix it correctly resolves to user-guide|observability-evaluation|logs on both preview and production-style paths (and home for /).

Not yet confirmed: that the SDK forwards an accepted beacon to edge.adobedc.net/ee/.../v1/interact after consent. A reviewer can confirm by loading the preview, accepting performance cookies, and watching the Network tab while searching/clicking — the dispatched event shape is verified correct, so this is the only remaining link in the chain.

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have reviewed and understand every line of code in this PR, including any generated by AI tools, and I can explain why it works
  • My change is focused and reasonably small; I have split unrelated work into separate PRs
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

The custom analytics events dispatched from Analytics.astro never reached
Adobe. The AWS WebSDK listens on a single event name, custom-awsm-acs-event-listener,
and reads event content from the XDM _aws namespace (detail.xdm._aws.<ns>). Our
code dispatched to two non-existent listener names
(custom-awsm-acs-analytics-event-listener, custom-awsm-acs-search-event-listener)
and wrapped content in detail.data, so the SDK's validators rejected and silently
dropped every event. The page-view/scroll/link data that did appear came from the
SDK's own auto-instrumentation, not from this code; internal search had no
auto-equivalent, which is why it showed zero.

Fix the dispatch layer to use the single correct listener and the
detail.xdm._aws.<ns> envelope, verified against the upstream packages
(AWSMarketingAdobeWebSDKClientSideLibs, AWSMarketingAdobeWebSDKHelpers) and the
production wsdk.js bundle. Also remove the invalid pageView pageInteraction event
(no such PageInteractionName exists; the SDK auto-fires the standard page view)
and the dead site-section fields, which have no destination variable.

Extend click tracking to cover existing interactive UI now that events land:
language toggle, GitHub dropdown links, sidebar group expand, content tabs,
landing CTAs, blog cards/nav, and landing/install code-copy buttons.
@github-actions github-actions Bot added documentation Documentation changes, improvements, additions, content updates, site improvements, examples, guides bug Something isn't working strands-running labels Jun 16, 2026
@yonib05
yonib05 enabled auto-merge (squash) June 16, 2026 00:25
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Documentation Preview Ready

Your documentation preview has been successfully deployed!

Preview URL: https://d3ehv1nix5p99z.cloudfront.net/pr-cms-2815/docs/user-guide/quickstart/overview/

Updated at: 2026-06-16T14:15:00.507Z

Comment thread site/src/components/Analytics.astro Outdated
Comment thread site/src/components/Analytics.astro Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Assessment: Comment

Well-scoped, carefully researched bug fix — the two root causes (wrong listener name, wrong payload envelope) are correct, and I independently verified every new click-tracking selector against the live source markup (LanguageToggle, GitHubDropdown, SidebarSublist, HeroSection, CodeBlock, BlogCard, AutoSyncTabs) and the xdm._aws contract against SiteScripts.astro's WebSDK loader. Nothing is dispatching into the void. Two substantive items keep this at "Comment" rather than approve.

Review themes
  • Event reliability (Important): Navigating link/CTA clicks dispatch without useBeacon, risking cancellation on unload — the same drop-on-navigation failure mode the PR fixes. See inline comment.
  • Test coverage (Important): The external-SDK contract that just silently regressed has no automated guard; a single full-shape assertion in vitest would prevent recurrence.
  • Verification (Suggestion): Description notes the built bundle hasn't been exercised in a browser yet — worth completing given the change is the runtime contract.
  • Comment accuracy (Minor): astro:page-load / view-transition assumptions don't appear to match the config; confirm or simplify.

Solid investigation work tracing this against the upstream packages and production bundle — the selector labeling is clean and the dead page-view removal is the right call.

pageHierarchy assumed the path began with /docs/, so on a deploy with a base
path (e.g. the /pr-xxxx/ preview) the prefix leaked into the label
(code-copy:pr-cms-2815|docs|...). Anchor on the 'docs' segment and take
everything after it so any leading base path is ignored.
Address review feedback on the analytics tracking:

- Navigating clicks (nav tabs, language toggle, GitHub menu, landing CTAs, blog
  cards/nav, outbound links) now dispatch with useBeacon=true so the request
  isn't cancelled when the page unloads - the same drop-on-navigation failure
  this PR otherwise fixes. Beacon is keyed off whether the click navigates, not
  the CTA type string, since nav-tab/lang-toggle navigate but are typed 'click'.
- Drop the View Transition / astro:page-load comments that implied SPA
  navigation; ClientRouter isn't enabled, so each navigation is a full reload
  and the IIFE re-runs fresh. The page-load listener is kept as a guarded no-op
  in case view transitions are enabled later.
@yonib05

yonib05 commented Jun 16, 2026

Copy link
Copy Markdown
Member Author

Thanks for the thorough review. Addressed in 0969bc1, with replies on both inline threads. Quick status on the other two themes:

  • Test coverage (Important): Agreed in principle that the external-SDK contract deserves a guard. I'm deliberately not adding it in this PR to keep the change focused — the inline is:inline script isn't exported/importable, so a vitest assertion needs the dispatch layer refactored out into a testable module, which is a larger change worth its own PR. Tracking it as a follow-up.
  • Final verification (Suggestion): I exercised the deployed PR preview build with browser automation and confirmed every event now fires on custom-awsm-acs-event-listener with the xdm._aws shape (table in the PR description). The one link I can't verify headlessly is that an accepted beacon reaches edge.adobedc.net/ee/.../v1/interact after consent — that needs a human accepting the cookie banner. Flagged in the description.

@github-actions

Copy link
Copy Markdown
Contributor

Updated Assessment: Approve

Re-reviewed after 0969bc12. Both inline items are resolved and verified against the source:

  • Event reliability — Navigating clicks now beacon via a navigates flag on dispatchCTAClick. I checked your refinement: the language toggle dispatches as type: 'click' but does window.location.href = paired (LanguageToggle.astro:247), so keying on the navigation behavior rather than the type string correctly catches a case my original suggestion would have missed. In-page clicks (tabs, sidebar expand, code copy) and same-page anchors stay non-beacon, which is right.
  • Comment accuracy — Stale "handles transitions" wording removed; astro:page-load is now documented as a guarded no-op for the full-reload model, with the listener kept for forward-compat if ClientRouter is enabled later.

Prettier passes on the file. The two open themes are reasonably dispositioned:

Follow-up themes (non-blocking)
  • Test coverage — Agreed this is a follow-up. The contract guard requires extracting the dispatch layer out of the is:inline IIFE into an importable module, which is a larger refactor than belongs in a focused bug fix. Worth tracking so the regression-prone envelope doesn't drift again.
  • Final verification — Preview build exercised via browser automation confirms events fire on the correct listener with the xdm._aws shape. The only unverifiable-headlessly step is an accepted-consent beacon reaching edge.adobedc.net, which needs a human accepting the cookie banner — appropriately flagged in the description.

Nice work, and the beacon refinement is a genuine improvement over the original suggestion.

@github-actions

Copy link
Copy Markdown
Contributor

Assessment: Approve

Re-reviewed 0969bc12. Both inline threads are resolved and the two Important items from the original review are addressed cleanly:

Verification of changes
  • Beacon (Important → resolved): dispatchCTAClick now forwards a navigates flag to useBeacon. Keying off navigation rather than the type string is the more correct fix — it covers nav-tab and lang-toggle (which navigate but are typed 'click') that a type-based gate would have missed. In-page clicks (anchor/TOC, sidebar-expand, tabs, code-copy) stay non-beacon. ✅
  • Comment accuracy (Minor → resolved): The View Transition / "handles transitions" claims are gone; astro:page-load is documented as a guarded no-op consistent with the full-reload model. ✅
  • Bonus: pageHierarchy now anchors on the docs segment, so preview-deploy base paths (/pr-xxxx/) no longer corrupt code-copy labels. ✅

On the two open themes: the test-coverage follow-up (extract the dispatch layer into an importable module + a single full-shape assertion) is a reasonable scope call to defer — please do track it, since this is the contract that already regressed once. The remaining manual check (an accepted beacon actually reaching the Adobe collect endpoint post-consent) is the one thing automation can't cover here, so a human pass through the cookie banner on the preview before merge is worthwhile.

Nicely handled — the beacon refinement improved on the original suggestion.

…turn

Address review nits on the analytics click tracking:

- Collapse whitespace on all CTA labels centrally in dispatchCTAClick, so labels
  from element textContent (icons/SVG/newlines) stay clean and consistent. Drops
  the now-redundant per-call normalization on home-cta.
- Guard the install code-copy label: fall back to 'install' instead of emitting
  'install:' with an empty tail if a [data-copy] ancestor is ever missing.
- Add the missing return to the outbound-link handler so appending a handler
  below it can't accidentally shadow it, matching every sibling handler.
@yonib05

yonib05 commented Jun 16, 2026

Copy link
Copy Markdown
Member Author

Addressed the actionable nits in 28f08be:

  1. Label consistency (ci: update sphinx requirement from <6.0.0,>=5.0.0 to >=5.0.0,<9.0.0 #1): Moved whitespace normalization into dispatchCTAClick (replace(/\s+/g, ' ').trim()) so every label is cleaned centrally — tab, sidebar-expand, and any future caller — rather than per-call. Removed the now-redundant .replace() on home-cta.
  2. Outbound return (ci: update mypy requirement from <1.0.0,>=0.981 to >=0.981,<2.0.0 #2): Added — every sibling handler returns, so this removes the future shadowing trap.
  3. Empty install: label (ci: update sphinx-rtd-theme requirement from <2.0.0,>=1.0.0 to >=1.0.0,<4.0.0 #3): Guarded — falls back to install instead of install: with an empty tail if a [data-copy] ancestor is ever missing. (Confirmed both current .install-copy buttons are wrapped in [data-copy] in HeroSection.astro, so it can't be empty today; this is defensive.)

@github-actions

Copy link
Copy Markdown
Contributor

Assessment: Approve (unchanged)

Re-reviewed 28f08bee against the source — all three actionable nits are correctly addressed:

Prettier passes. The dispositions on the defensive github-menu fallback (#4) and the human-only post-consent edge verification (#5) are both reasonable, and the selector smoke-test remains a sensible tracked follow-up once the dispatch layer is extractable.

No further blocking items from me — good to merge once a human completes the post-consent beacon check on the preview.

Comment thread site/src/components/Analytics.astro
@yonib05
yonib05 merged commit 56b8dc9 into strands-agents:main Jun 16, 2026
12 checks passed
@opieter-aws opieter-aws mentioned this pull request Jun 17, 2026
9 tasks
@yonib05
yonib05 deleted the fix/analytics-xdm-event-shape branch July 16, 2026 01:50

This branch was previously deployed

1 inactive deployment
auto-approve 28f08bee Deployed Jun 16, 2026 by yonib05 via Build and Deploy Preview #270
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Documentation changes, improvements, additions, content updates, site improvements, examples, guides size/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants