Designing a Micro-Frontend Architecture for the Genesys Agent Workspace using Module Federation
What This Guide Covers
This masterclass details the implementation of a Micro-Frontend (MFE) strategy for Genesys Cloud custom widgets. By the end of this guide, you will be able to architect an agent workspace where multiple independent development teams can deploy UI components (Interaction Widgets, Sidebars, and Analytics Panels) without ever needing to redeploy the “Shell” application. You will learn how to use Webpack Module Federation to load remote components at runtime, implement a Unified State Store, and ensure a seamless, high-performance experience for agents handling complex omnichannel interactions.
Prerequisites, Roles & Licensing
MFE architecture requires advanced frontend engineering and access to the Genesys Cloud Client App SDK.
- Licensing: Genesys Cloud CX 1, 2, or 3.
- Permissions:
Integrations > Custom Client Application > View/Add
- OAuth Scopes:
integrations. - Infrastructure: A “Host” application and one or more “Remote” applications hosted on a CDN (e.g., AWS CloudFront / Vercel).
The Implementation Deep-Dive
1. The “Host and Remote” Concept
In a micro-frontend architecture, the Host (Shell) provides the overall structure (Navigation, Authentication), while Remotes provide the specific features.
Architectural Reasoning:
By using Module Federation, the Host application doesn’t “bundle” the remote code at build time. Instead, it fetches the remoteEntry.js file from each team’s CDN at runtime. This allows Team A to push a bug fix for the “Billing Widget” in 2 minutes without impacting Team B’s “Knowledge Base” component.
2. Configuring Webpack Module Federation
Both the Host and the Remote must be configured to share and consume modules.
Implementation Pattern (Remote - Billing Widget):
// webpack.config.js
new ModuleFederationPlugin({
name: 'billing_widget',
filename: 'remoteEntry.js',
exposes: {
'./Widget': './src/components/BillingWidget',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
});
Implementation Pattern (Host - Shell):
// webpack.config.js
new ModuleFederationPlugin({
name: 'shell',
remotes: {
billing: 'billing_widget@https://cdn.example.com/billing/remoteEntry.js',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
});
3. Implementing a Unified State Store
Micro-frontends must communicate without being tightly coupled.
The Strategy:
Use a Global Event Bus or a shared Redux/Zustand Store injected by the Host.
- The Host initializes the Genesys Cloud Client App SDK.
- It passes the
interactionIdandparticipantDatato the remotes via React Props or a Custom Event. - The Result: When an agent switches interactions in the Genesys sidebar, the Host detects the change and notifies all MFE widgets simultaneously, ensuring all panels stay in sync.
4. Handling Versioning and Rollbacks
One of the risks of MFEs is that a Remote team might push a breaking change.
Implementation Step:
- Use Blue-Green Deployment on your CDN.
- The Host application should fetch the
remoteEntry.jsusing a Versioned URL (e.g.,.../v1.2.3/remoteEntry.js). - To roll back, simply update the Host’s configuration to point back to
v1.2.2. This ensures that “Breaking” changes are never accidentally pushed to 100% of the agent population.
Validation, Edge Cases & Troubleshooting
Edge Case 1: Dependency Hell (Shared Versions)
- The failure condition: The Host uses React 18, but a Remote uses React 17. The application crashes due to multiple copies of React running in the same browser tab.
- The root cause: Misconfigured
shareddependencies in Webpack. - The solution: Always use the
singleton: trueandrequiredVersionflags in theModuleFederationPlugin. This forces all MFEs to use the version provided by the Host, preventing library duplication and memory leaks.
Edge Case 2: Slow Initial Load (The “Waterfall” Effect)
- The failure condition: The agent opens the workspace, and the widgets appear one-by-one with a noticeable delay.
- The root cause: Synchronous loading of multiple remote entries.
- The solution: Implement Lazy Loading with Suspense and a Shimmer/Skeleton UI. Load the most critical widget first (e.g., the Interaction Details) and load non-critical ones (e.g., Performance Stats) in the background.