Fix Feedex widget never rendering by switching script strategy - #27
Merged
Conversation
The widget shipped but no launcher ever appeared on production. The script was fetched (200), it read its key and fetched its remote config successfully (200, valid config for the NetPost project), and the tag carried all nine data-feedex-* attributes. Despite that, window.Feedex stayed undefined and no shadow root was created, with no console errors, because the widget fails silently by design. Isolated it on the live page: removing Next's injected tag and appending a plain script element with the same key immediately produced window.Feedex as an object and a new shadow host. So the script and the key were fine and the injection strategy was not. strategy="lazyOnload" injects after the window load event has already fired. The widget's eager work still runs, which is why the config request went out, but the part that attaches the global and renders the launcher hangs off an event that has already passed. afterInteractive injects during hydration and the widget boots normally. The Feedex Next.js quickstart recommends lazyOnload, so this is worth reporting upstream.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR fixes the Feedex feedback widget failing to render in production by changing the Next.js Script injection strategy so the widget initializes before its internal “on load” hooks are missed, and updates the project documentation to reflect the rationale.
Changes:
- Switch Feedex script loading from
strategy="lazyOnload"tostrategy="afterInteractive"in the root layout so the launcher reliably appears. - Expand in-code documentation in
layout.tsxexplaining whylazyOnloadcauses a silent no-op for this widget. - Update the README “Feedback” section to match the new strategy and document the observed behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| README.md | Updates Feedex integration docs to reflect afterInteractive and explain why lazyOnload fails. |
| frontend/app/layout.tsx | Changes next/script strategy to afterInteractive and documents the production behavior/regression cause. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
The widget shipped in #26 but no launcher ever appeared on production.
What was ruled out
Everything looked healthy:
widget.js→ 200GET /api/v1/widget-config?key=...→ 200, valid config for theNetPostprojectdata-feedex-*attributes, correct keyYet
window.Feedexwasundefinedand no shadow root existed. Since the config request did go out, the script was clearly executing — so neither the key nor the domain allowlist was at fault.Isolating it
On the live page, I removed Next's injected tag and appended a plain script element with the same key:
window.Feedexnext/scriptlazyOnloadundefineddocument.createElement("script")objectSame page, same key, same script. The strategy was the problem.
Cause and fix
lazyOnloadinjects after the windowloadevent has already fired. The widget's eager work still runs — hence the config request — but the part that attacheswindow.Feedexand renders the launcher hangs off an event that has already passed.afterInteractiveinjects during hydration, while that event is still ahead of it.Worth noting
The Feedex Next.js quickstart recommends
lazyOnload, so this is worth fixing in your own docs — anyone following them on App Router will hit the same silent no-op.