Skip to content

Braze Banners System Layout fixes & Observability#15485

Open
andresilva-guardian wants to merge 10 commits intomainfrom
afs/braze-banners-analytics
Open

Braze Banners System Layout fixes & Observability#15485
andresilva-guardian wants to merge 10 commits intomainfrom
afs/braze-banners-analytics

Conversation

@andresilva-guardian
Copy link
Contributor

@andresilva-guardian andresilva-guardian commented Mar 5, 2026

What does this change?

This PR delivers two groups of improvements to BrazeBannersSystem:

1. Layout & Scroll Fixes (Wrapper Mode)

  • Removed the border: none override that was applied at the phablet breakpoint — the banner now has a consistent border-top at all screen sizes.
  • Added overflow-y: auto and overflow-x: hidden to the wrapper container, allowing taller banners to scroll vertically within the max-height: 65svh constraint on portrait/small screens.
  • Added overscroll-behavior: none to prevent scroll chaining — once the user reaches the top or bottom of the banner, the scroll event is no longer propagated to the host page.
  • Fixed the CSS Grid template for the inner copy-container / close-button layout: changed auto 0px100% 0px so copy-container always occupies the full available width.

2. Observability: Impression Tracking & Interaction Logging

Impression Tracking (on first view)

The BrazeBannersSystemDisplay component now uses the useIsInView hook to detect when the banner first enters the viewport. On that event, three things happen in sequence:

Banner enters viewport (IntersectionObserver fires)
        │
        ├─► brazeBannersSystemLogger.info("Banner ... has been seen. Logging impression.")
        │
        ├─► document.dispatchEvent(new CustomEvent('banner:open', { detail: { bannerId } }))
        │       └─ Allows other parts of the page to react (e.g. hide competing banners)
        │
        ├─► braze.logBannerImpressions([placementId])
        │       └─ Feeds Braze campaign reporting & frequency capping
        │
        └─► submitComponentEvent({ component: { componentType: 'RETENTION_ENGAGEMENT_BANNER', id: ophanComponentId ?? placementId }, action: 'VIEW' })
                └─ Feeds Ophan / BigQuery for editorial/commercial dashboards

The ophanComponentId can be overridden per campaign via a Key-Value pair in the Braze Dashboard; it falls back to placementId.

Interaction Logging (on user action)

Every user interaction now logs both a Braze banner click (for native Braze campaign reports) and a Braze custom event (for granular analytics):

User Action logBannerClick label logCustomEvent name Payload
Newsletter Subscribe newsletter_subscribe_button braze_banner_newsletter_subscribe placementId, newsletterId, success
Reminder Subscribe reminder_subscribe_button braze_banner_reminder_subscribe placementId, reminderPeriod, reminderComponent, reminderOption, success
Navigate to URL navigate_to_url_button braze_banner_navigate_to_url placementId, url, target
Dismiss Banner dismiss_button braze_banner_dismissed placementId

CSS Validation Failure Logging

runCssCheckerOnBrazeBanner now returns a boolean result. If validation fails:

  • brazeBannersSystemLogger.warn(...) is called so it's visible in DCR logs.
  • Braze custom event braze_banner_css_validation_failed is fired with placementId.
  • The banner is still rendered — this is a non-blocking signal for awareness, not enforcement.

id propagated through the system

canShowBrazeBannersSystem now accepts an explicit id string (the message picker candidate ID) and surfaces it through BrazeBannersSystemMeta. This id is used as bannerId in the banner:open DOM event, enabling precise identification of which candidate fired.

Why?

Layout fixes

Banners on portrait tablets (phablet breakpoint) were overflowing their container because no scroll affordance existed. The inconsistent border: none at phablet also caused a visual discontinuity with other breakpoints. These are straightforward correctness fixes.

Observability

The Braze Banners System was previously a black box from an analytics standpoint — we had no reliable signal for:

  • When a banner was actually seen by the user (as opposed to just rendered in the DOM).
  • What users did with it (subscribe, navigate, dismiss).
  • Whether the Braze creative had broken CSS before it went live.

This PR fills all three gaps:

  1. Impression data now flows into both Braze (for frequency capping correctness) and Ophan/BigQuery (for editorial and commercial dashboards).
  2. Interaction data allows the CRM team to measure CTA effectiveness per campaign without relying on frontend engineers to pull data manually.
  3. CSS validation failures surface actionable Braze-side alerts before a broken creative reaches a significant audience.

Screenshots

No relevant screen changes to display.

@andresilva-guardian andresilva-guardian requested a review from a team as a code owner March 5, 2026 14:17
@github-actions
Copy link

github-actions bot commented Mar 5, 2026

Hello 👋! When you're ready to run Chromatic, please apply the run_chromatic label to this PR.

You will need to reapply the label each time you want to run Chromatic.

Click here to see the Chromatic project.

@andresilva-guardian andresilva-guardian changed the title Afs/braze banners analytics Braze Banners System Layout fixes & Observability Mar 5, 2026
@andresilva-guardian andresilva-guardian added run_chromatic Runs chromatic when label is applied feature Departmental tracking: work on a new feature labels Mar 5, 2026
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Departmental tracking: work on a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant