# RFC: Platform-level UTM attribution support for authenticated MFE users

**URL:** <https://discuss.openedx.org/t/rfc-platform-level-utm-attribution-support-for-authenticated-mfe-users/19182>\
**Category:** Development\
**Created:** [July 30, 2026, 1:57pm UTC](https://discuss.openedx.org/t/rfc-platform-level-utm-attribution-support-for-authenticated-mfe-users/19182 "2026-07-30T13:57:58Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![arbrandes](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/arbrandes/32/158_2.png) [@arbrandes](https://discuss.openedx.org/u/arbrandes)\
**Post date:** [September 21, 2026, 6:10pm UTC](https://discuss.openedx.org/t/rfc-platform-level-utm-attribution-support-for-authenticated-mfe-users/19182/4 "2026-09-21T18:10:30Z")

</div>

Thanks for the revision. I don’t think the generic layer is needed, though, because frontend-base already has most of it:

The initialization sequence publishes lifecycle events (`SITE_CONFIG_INITIALIZED`, `SITE_AUTH_INITIALIZED`, `SITE_READY`, `AUTHENTICATED_USER_CHANGED`) that any module can subscribe to. That covers `onAppInit` and `onUserSessionStart`. `initialize()` also accepts an `authMiddleware` array ([ADR 0006](https://github.com/openedx/frontend-base/blob/main/docs/decisions/0006-middleware-support-for-http-clients.rst)) that is applied to every HTTP client the auth service creates, including the cached ones, which covers both HTTP client hooks. And the `App` interface has a per-app `externalScripts` field ([ADR 0014](https://github.com/openedx/frontend-base/blob/main/docs/decisions/0014-per-app-external-scripts.rst)) that is exactly the “run some code at boot with this app’s config” shape; consent banners were the motivating example in that ADR. Section 2 compares against frontend-plugin-framework’s `PluginSlot`, but frontend-base has its own slot system plus these non-UI hooks, so the claim that there is no extension point for any of this doesn’t hold.

`onLogout` has no frontend counterpart to hook. Logout is still just a redirect to the LMS logout URL, so there is no client-side step where the hook could fire. The server-side cookie deletion you already propose is the right place for that. It does edit the logout view, though, which should be reconciled with the “no existing LMS code is modified” claim.

The one thing missing is that `authMiddleware` is only reachable as an `initialize()` option, and the shell calls `initialize()` with just messages, so operators can’t set it from `site.config.tsx`. That is the frontend-base change I’d propose instead: a middleware field on `App`, so that multiple apps compose rather than clobber each other, following the same reasoning that led [ADR 0014](https://github.com/openedx/frontend-base/blob/main/docs/decisions/0014-per-app-external-scripts.rst) to reject a site-level array.

With that in place, UTM attribution becomes an ordinary `App` in its own package: `externalScripts` for the URL capture and cookie write, the new middleware field for the header interceptor, and `App.config` for cookie name and domain. Operators add it to `apps` in `site.config.tsx` like any other app. No new manager, no new plugin type, and the framework-level part of the RFC shrinks to the middleware field.

A few smaller things to adjust when reworking: site config keys are camelCase (`lmsBaseUrl`) and there is no cookie domain key, so the app needs to carry that in its own config; IDs use reverse-domain notation (`org.openedx.frontend.app.*`); and the rollout should be framed around a single shell rather than independently upgraded MFEs.

If the next version comes as a PR that adds an ADR to frontend-base instead of a Word document, that would be ideal!

---

_[View the full topic](https://discuss.openedx.org/t/rfc-platform-level-utm-attribution-support-for-authenticated-mfe-users/19182)._
