Skip to content

Conversation

@ChristopherChudzicki
Copy link
Contributor

@ChristopherChudzicki ChristopherChudzicki commented Nov 21, 2025

What are the relevant tickets?

Closes https://github.com/mitodl/hq/issues/9317

Description (What does it do?)

This PR fixes an issue where the feature-flagged product pages would occasionally show 404, particularly on slow networks.

How can this be tested?

  1. Prerequisites:
    • Learn <> MITxOnline integration set up
    • Posthog setup with product-course-page flag enabled
    • NODE_ENV=production in frontend.local.env (I find that page loads too slowly in dev mode, meaning that posthog always loads latest; the race condition is much more reproducible in production mode.)
  2. On main:
    1. visit http://open.odl.local:8062/programs/<readable-id>
    2. enable network throttling (4G should be good enough) and reload the page. If you don't get 404, keep reloading, but I've found it very reproducible on 4G throttling in production mode.
  3. Repeat Step 2 on this branch
    • I suggest checking both dev mode (NODE_ENV=development) and production build (NODE_ENV=production).

@ChristopherChudzicki ChristopherChudzicki force-pushed the cc/distinguish-bootstrapped-flags branch from e06e72e to dd1abc2 Compare November 21, 2025 01:22
const enabled = useFeatureFlagEnabled(FeatureFlags.ProductPageCourse)
if (enabled === false) {
return notFound()
const flagsLoaded = useFeatureFlagsLoaded()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change these lines to

  const enabled = useFeatureFlagEnabled(FeatureFlags.ProductPageCourse)
  const bootstrapped = useFeatureFlagEnabled(INTERNAL_BOOTSTRAPPING_FLAG)
  const flagsLoaded = useFeatureFlagsLoaded()

  console.log({ enabled, bootstrapped, flagsLoaded })

you would see values something like

// posthog not initialized
{enabled: undefined, bootstrapped: undefined, flagsLoaded: false}
// posthog initialized, flags loaded from localstorage / bootstrapping
{enabled: true, bootstrapped: true, flagsLoaded: false}
// posthog initialized, flags loaded from server
{enabled: true, bootstrapped: undefined, flagsLoaded: true}

/**
* bootstrapFlag will be undefined:
* 1. BEFORE posthog has initialized (nothing bootstrapped yet)
* 2. AFTER posthog has loaded flags from its server.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posthog docs have always said, apparently that posthog.isFlagEnabled (and useFlagEnabled) would return undefined if the flag is not configured on the server (e.g., a typo flag, or our bootstrapping flag here).

This actually isn't true in the version of posthog-js on main. It's kind of a breaking change, but since the docs have always described the "return undefined" behavior, they classified it as a bugfix. See PostHog/posthog-js#2276 (comment)

* Posthog does not make detecting "flags have loaded from server" easy.
* This approach relies on the fact that bootstrapped flags are completely
* discarded after flags are loaded from server, so `useFlagEnabled` will
* return `undefined` for any flag that was only bootstrapped locally.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

posthog's AI suggested this approach and it seems to work well...

const POSTHOG_API_HOST = process.env.NEXT_PUBLIC_POSTHOG_API_HOST
const FEATURE_FLAGS = process.env.FEATURE_FLAGS

if (POSTHOG_API_KEY) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For nextjs, Posthog docs recommend initializing either

  • instrumentation-client.ts
    • I tried this; it caused a bunch of hydration errors. I think that in order for the instrumentation-client.ts approach to work w/o hydration errors, you need also to initialize in the server and load flags server-side. Since we don't have user info on the server, we can't do that.
  • provider component inside a useEffect

The current top-level initialization caused hydration errors, too. Initializing inside the provider effect does not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this prevent all feature flagged content from being server rendered, even if we have environment defaults? I guess they need to be as content appearing is better than content disappearing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. Though that also wasn't happening with the current placement of posthog init code. On RC currently:

  • code is module level
  • NEXT_PUBLIC_FEATURE_home_page_recommendation_bot is set to true.

I do think we could get server-side flagging of the bootstrapped values to work, though.

Copy link
Contributor

@jonkafton jonkafton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works a charm! 👍

const POSTHOG_API_HOST = process.env.NEXT_PUBLIC_POSTHOG_API_HOST
const FEATURE_FLAGS = process.env.FEATURE_FLAGS

if (POSTHOG_API_KEY) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this prevent all feature flagged content from being server rendered, even if we have environment defaults? I guess they need to be as content appearing is better than content disappearing.

@ChristopherChudzicki ChristopherChudzicki merged commit 95e6f89 into main Nov 21, 2025
18 of 19 checks passed
@ChristopherChudzicki ChristopherChudzicki deleted the cc/distinguish-bootstrapped-flags branch November 21, 2025 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants