You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add configuration option to disable lazy loading of session replay recorder module #3939
The Datadog RUM SDK lazy-loads the session replay recorder module using dynamic import(), which causes issues in environments that don't support code splitting or dynamic chunk loading, such as:
Rails asset pipeline (Sprockets)
Legacy webpack configurations without chunkFilename configured
Build systems that require all assets to be declared in a manifest
When session replay is enabled (sessionReplaySampleRate > 0), the SDK attempts to fetch the recorder module at runtime:
GET /assets/startRecording
This results in a 404 error and session replay fails to initialize:
Datadog Browser SDK: Recorder failed to start: an error occurred while initializing the module:
TypeError: Failed to fetch dynamically imported module: https://example.com/assets/startRecording
Requested Feature
Add a configuration option to the datadogRum.init() call that statically bundles the recorder module instead of lazy-loading it:
datadogRum.init({applicationId: 'xxx',clientToken: 'xxx',site: 'datadoghq.com',service: 'my-app',sessionReplaySampleRate: 100,// NEW OPTION:bundleRecorderModule: true// or lazyLoadRecorder: false})
When this option is enabled, the SDK should:
Import the recorder module statically at build time
Migrate to a different build system (significant effort)
Environment
Browser: All
SDK Version: @datadog/browser-rum 6.23.0
Build System: Rails asset pipeline (Sprockets)
Webpack: 4.x without code splitting configured
Impact
This affects any application using Rails, Django, or other traditional server-rendered frameworks with asset pipelines that don't support dynamic module loading.
Thanks for reporting this. For context, we added code-splitting to reduce the SDK overhead on the host app. The browser now downloads only what it needs, which improves load time. Most bundlers support code-splitting today, so we rely on it.
In your case, Webpack 4 supports code-splitting as well (see doc). Can you explain how you disabled code-splitting and why, so we can help you? If you prefer not to post your config here, you can contact support.
Hi @amortemousque , thanks for the reply and the context — totally understand the motivation behind code-splitting and reducing SDK overhead 👍
To clarify our setup: this is a Rails + Sprockets asset pipeline application using Webpack 4, and the system itself is quite old / legacy, which largely explains why the asset setup looks the way it does today. In this environment, all JS assets must be emitted as concrete files and declared in the asset manifest. Because of that, we intentionally avoid runtime-loaded JS chunks via import() and try to keep changes to the bundling setup as minimal as possible, given the size, age, and complexity of the existing configuration.
Below is a minimal, anonymized excerpt from our Webpack config showing the relevant constraints. This is taken from a much larger (~346 line) configuration; I’ve only included the parts that affect dynamic chunk loading:
// Excerpt from a larger (~346 line) webpack config.
// Showing only the relevant output / chunking constraints.
module.exports = {
output: {
// Assets are emitted into Rails' asset pipeline and served from /assets
path: path.resolve(__dirname, 'vendor/assets/javascripts'),
filename: '[name].js',
// We intentionally do NOT configure JS chunkFilename / publicPath
// because all assets must be present and declared ahead of time.
// chunkFilename: '[name]-[contenthash].js',
// publicPath: '/assets/',
},
// Code splitting is enabled only for a limited set of *initial* entrypoints.
// We do not support general async chunk loading at runtime.
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /node_modules/,
chunks: 'initial',
name: 'vendor',
enforce: true,
chunks: (chunk) => {
const targets = [
'bundles/header',
'bundles/footer',
'bundles/banner',
'bundles/cookie',
'share_lots/payments',
];
return chunk.name && targets.some((t) => new RegExp(t, 'i').test(chunk.name));
},
},
},
},
},
};
Because of this setup, when the RUM SDK tries to lazy-load the session replay recorder via import(), the browser ends up requesting a separate module URL (e.g. /assets/startRecording), which does not exist in the Sprockets manifest. This results in a 404 and prevents session replay from initializing.
Our initial goal was to avoid making invasive changes to the existing Webpack/Rails setup just to accommodate this, especially given how old and widely-used the system is.
In the end, we did move forward with the CDN setup, which works for us operationally. That said, if there is a reasonably simple way to make the npm package work in this kind of legacy asset-pipeline environment, we’d still be very interested — both as a cleaner solution and as a learning opportunity for me.
Thanks again for the help and for taking the time to look into this 🙏
Activity
amortemousque commentedon Nov 25, 2025
Hello @asif-st-republic ,
Thanks for reporting this. For context, we added code-splitting to reduce the SDK overhead on the host app. The browser now downloads only what it needs, which improves load time. Most bundlers support code-splitting today, so we rely on it.
In your case, Webpack 4 supports code-splitting as well (see doc). Can you explain how you disabled code-splitting and why, so we can help you? If you prefer not to post your config here, you can contact support.
You can also choose one of these options:
asif-st-republic commentedon Dec 15, 2025
Hi @amortemousque , thanks for the reply and the context — totally understand the motivation behind code-splitting and reducing SDK overhead 👍
To clarify our setup: this is a Rails + Sprockets asset pipeline application using Webpack 4, and the system itself is quite old / legacy, which largely explains why the asset setup looks the way it does today. In this environment, all JS assets must be emitted as concrete files and declared in the asset manifest. Because of that, we intentionally avoid runtime-loaded JS chunks via import() and try to keep changes to the bundling setup as minimal as possible, given the size, age, and complexity of the existing configuration.
Below is a minimal, anonymized excerpt from our Webpack config showing the relevant constraints. This is taken from a much larger (~346 line) configuration; I’ve only included the parts that affect dynamic chunk loading:
Because of this setup, when the RUM SDK tries to lazy-load the session replay recorder via import(), the browser ends up requesting a separate module URL (e.g. /assets/startRecording), which does not exist in the Sprockets manifest. This results in a 404 and prevents session replay from initializing.
Our initial goal was to avoid making invasive changes to the existing Webpack/Rails setup just to accommodate this, especially given how old and widely-used the system is.
In the end, we did move forward with the CDN setup, which works for us operationally. That said, if there is a reasonably simple way to make the npm package work in this kind of legacy asset-pipeline environment, we’d still be very interested — both as a cleaner solution and as a learning opportunity for me.
Thanks again for the help and for taking the time to look into this 🙏