Feast Contextual Nudge Braze Banners#16254
Open
andresilva-guardian wants to merge 12 commits into
Open
Conversation
…with text variables
…essibility and a margin
…ssion configuration
juabara
approved these changes
Jun 26, 2026
|
Hello 👋! When you're ready to run Chromatic, please apply the You will need to reapply the label each time you want to run Chromatic. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this change?
We integrate Braze Banners into the
FeastContextualNudgecomponent, so that when a user is signed in and Braze has a banner ready for the corresponding placement slot, we render the Braze banner in place of the native static nudge.Concretely, we:
BrazeBannersSystemPlacementIdentries (FeastContextualNudge1–FeastContextualNudge5) so we can address up to five distinct nudge positions per article.ArticleRendererto distribute up to five placement slots evenly across all recipe sections. We calculate aninterval = ceil(sections.length / 5)and assign anudgeIndex(1–5) to every section that falls on a multiple of that interval, passingnudgeIndexandidApiUrldown to the component.FeastContextualNudgeto acceptnudgeIndexandidApiUrlas props, calluseBraze, and, if Braze returns a banner for the computed placement ID, renderBrazeBannersSystemDisplayinstead of the default nudge card.GetContextmessage type toBrazeBannersSystemand acontextprop toBrazeBannersSystemDisplay, so the Braze banner iframe can request page, recipe and user context (recipe details,pageId,nudgeIndex,darkMode, etc.) to personalise its content.--feast-nudge-headingand--feast-nudge-subtextCSS custom properties into a single--feast-nudge-textvariable, as requested by the Design team.nudgeIndexandidApiUrlprops.Page-aware placement loading
ISLAND_PLACEMENT_MAP- a map fromgu-islandcomponent names to their Braze placement IDs.getPagePlacements()queries the server-rendered DOM at runtime and returns only the placements whose island element is present, so we never request placements for components that cannot appear on the current page.buildBrazeMessagingto callgetPagePlacements()beforerefreshBannersand skip the refresh entirely when no relevant placements are on the page.Rate-limit observability
refreshBannersnow logs an info message listing every placement ID and count before the request, and emits a warning when the caller exceeds Braze's limit of 10 placements per refresh.Stale-cache handling
stalePlacementsSetthat tracks placement IDs whose lastrequestBannersRefreshwas rejected by Braze's rate-limiter (5 tokens per session, refilling every 3 minutes). The error callback marks the affected placements as stale and logs which ones were added; the success callback clears them.isPlacementStale(id)for island components to query the stale state of a specific placement before callinggetBanner().PLACEMENT_SUPPRESS_ON_STALE- a flatPartial<Record<BrazeBannersSystemPlacementId, boolean>>that controls per-placement suppression behaviour when stale.BannerandEndOfArticleare set totrue(suppress - avoids showing outdated MRR campaigns); the fiveFeastContextualNudgeplacements are set tofalse(fall through to the native card). TheISLAND_PLACEMENT_MAPremains a pure DOM-detection structure and carries no suppression logic.canShowBrazeBannersSystemchecksstalePlacementsbefore callinggetBanner(), andFeastContextualNudgeperforms the same check before attempting to render a Braze banner.Why?
The MRR team needs to be able to personalise the copywriting and CTA of the Feast contextual nudge based on the reader's context - for example whether they already have the Feast app installed, whether they hold a Feast subscription, and what country they are browsing from. The native static nudge cannot account for these variables. By delegating rendering to Braze when a banner is available for the signed-in user, we enable a richer and more relevant signed-in experience.
We cap the number of Braze placement slots at five because the Braze Banners API allows up to ten placements per refresh request, and we want to leave headroom for other placements on the page. Rather than placing a nudge at every recipe section, we distribute the five slots evenly so they are spread across the full length of the article.
Page-aware loading avoids burning rate-limit tokens on placements that cannot appear on the current page. Stale-cache handling ensures that, when rate-limit tokens are exhausted, components either suppress the cached banner (for time-sensitive MRR placements) or fall through to a native fallback (for Feast nudges), rather than silently showing potentially outdated content or hiding the slot entirely.
Screenshots