diff --git a/guide.md b/guide.md
index 76f781d096..5560238522 100644
--- a/guide.md
+++ b/guide.md
@@ -158,6 +158,7 @@ The parameter of `rrweb.record` accepts the following options.
| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) |
| recordCanvas | false | Whether to record the canvas element. Available options:
`false`,
`true` |
| recordCrossOriginIframes | false | Whether to record cross origin iframes. rrweb has to be injected in each child iframe for this to work. Available options:
`false`,
`true` |
+| recordAfter | 'load' | If the document is not ready, then the recorder will start recording after the specified event is fired. Available options: `DOMContentLoaded`, `load` |
| inlineImages | false | whether to record the image content |
| collectFonts | false | whether to collect fonts in the website |
| userTriggeredOnInput | false | whether to add `userTriggered` on input events that indicates if this event was triggered directly by the user or not. [What is `userTriggered`?](https://github.com/rrweb-io/rrweb/pull/495) |
diff --git a/guide.zh_CN.md b/guide.zh_CN.md
index 1093dbb386..1272cf4772 100644
--- a/guide.zh_CN.md
+++ b/guide.zh_CN.md
@@ -154,6 +154,7 @@ setInterval(save, 10 * 1000);
| dataURLOptions | {} | Canvas 图像快照的格式和质量,这个参数将传递给 OffscreenCanvas.convertToBlob(),使用这个参数能有效减小录制数据的大小 |
| recordCanvas | false | 是否记录 canvas 内容, 可用选项:`false`, `true` |
| recordCrossOriginIframes | false | 是否记录 cross origin iframes。 必须在每个子 iframe 中注入 rrweb 才能使其工作。 可用选项:`false`, `true` |
+| recordAfter | 'load' | 如果 document 还没有加载完成,recorder 将会在指定的事件触发后开始录制。可用选项: `DOMContentLoaded`, `load` |
| inlineImages | false | 是否将图片内容记内联录制 |
| collectFonts | false | 是否记录页面中的字体文件 |
| userTriggeredOnInput | false | [什么是 `userTriggered`](https://github.com/rrweb-io/rrweb/pull/495) |
diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts
index c28ec28a2c..6c79007690 100644
--- a/packages/rrweb/src/record/index.ts
+++ b/packages/rrweb/src/record/index.ts
@@ -76,6 +76,9 @@ function record(
mousemoveWait,
recordCanvas = false,
recordCrossOriginIframes = false,
+ recordAfter = options.recordAfter === 'DOMContentLoaded'
+ ? options.recordAfter
+ : 'load',
userTriggeredOnInput = false,
collectFonts = false,
inlineImages = false,
@@ -408,16 +411,6 @@ function record(
try {
const handlers: listenerHandler[] = [];
- handlers.push(
- on('DOMContentLoaded', () => {
- wrappedEmit(
- wrapEvent({
- type: EventType.DomContentLoaded,
- data: {},
- }),
- );
- }),
- );
const observe = (doc: Document) => {
return initObservers(
@@ -583,6 +576,17 @@ function record(
) {
init();
} else {
+ handlers.push(
+ on('DOMContentLoaded', () => {
+ wrappedEmit(
+ wrapEvent({
+ type: EventType.DomContentLoaded,
+ data: {},
+ }),
+ );
+ if (recordAfter === 'DOMContentLoaded') init();
+ }),
+ );
handlers.push(
on(
'load',
@@ -593,7 +597,7 @@ function record(
data: {},
}),
);
- init();
+ if (recordAfter === 'load') init();
},
window,
),
diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts
index fb3a300b40..0ab8269854 100644
--- a/packages/rrweb/src/types.ts
+++ b/packages/rrweb/src/types.ts
@@ -61,6 +61,7 @@ export type recordOptions = {
dataURLOptions?: DataURLOptions;
recordCanvas?: boolean;
recordCrossOriginIframes?: boolean;
+ recordAfter?: 'DOMContentLoaded' | 'load';
userTriggeredOnInput?: boolean;
collectFonts?: boolean;
inlineImages?: boolean;
diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap
index 631580b1aa..ea037dff38 100644
--- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap
+++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap
@@ -8408,6 +8408,89 @@ exports[`record integration tests should record DOM node movement 2 1`] = `
]"
`;
+exports[`record integration tests should record after DOMContentLoaded event 1`] = `
+"[
+ {
+ \\"type\\": 0,
+ \\"data\\": {}
+ },
+ {
+ \\"type\\": 4,
+ \\"data\\": {
+ \\"href\\": \\"about:blank\\",
+ \\"width\\": 1920,
+ \\"height\\": 1080
+ }
+ },
+ {
+ \\"type\\": 2,
+ \\"data\\": {
+ \\"node\\": {
+ \\"type\\": 0,
+ \\"childNodes\\": [
+ {
+ \\"type\\": 2,
+ \\"tagName\\": \\"html\\",
+ \\"attributes\\": {},
+ \\"childNodes\\": [
+ {
+ \\"type\\": 2,
+ \\"tagName\\": \\"head\\",
+ \\"attributes\\": {},
+ \\"childNodes\\": [],
+ \\"id\\": 3
+ },
+ {
+ \\"type\\": 2,
+ \\"tagName\\": \\"body\\",
+ \\"attributes\\": {},
+ \\"childNodes\\": [
+ {
+ \\"type\\": 3,
+ \\"textContent\\": \\"\\\\n \\",
+ \\"id\\": 5
+ },
+ {
+ \\"type\\": 2,
+ \\"tagName\\": \\"script\\",
+ \\"attributes\\": {},
+ \\"childNodes\\": [
+ {
+ \\"type\\": 3,
+ \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
+ \\"id\\": 7
+ }
+ ],
+ \\"id\\": 6
+ },
+ {
+ \\"type\\": 3,
+ \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\",
+ \\"id\\": 8
+ }
+ ],
+ \\"id\\": 4
+ }
+ ],
+ \\"id\\": 2
+ }
+ ],
+ \\"compatMode\\": \\"BackCompat\\",
+ \\"id\\": 1
+ },
+ \\"initialOffset\\": {
+ \\"left\\": 0,
+ \\"top\\": 0
+ }
+ }
+ },
+ {
+ \\"type\\": 1,
+ \\"data\\": {}
+ }
+]"
+`;
+
exports[`record integration tests should record canvas mutations 1`] = `
"[
{
diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts
index 516d3a289a..0371914fe6 100644
--- a/packages/rrweb/test/integration.test.ts
+++ b/packages/rrweb/test/integration.test.ts
@@ -984,4 +984,19 @@ describe('record integration tests', function (this: ISuite) {
)) as eventWithTime[];
assertSnapshot(snapshots);
});
+
+ it('should record after DOMContentLoaded event', async () => {
+ const page: puppeteer.Page = await browser.newPage();
+ await page.goto('about:blank');
+ await page.setContent(
+ getHtml.call(this, 'blank.html', {
+ recordAfter: 'DOMContentLoaded',
+ }),
+ );
+
+ const snapshots = (await page.evaluate(
+ 'window.snapshots',
+ )) as eventWithTime[];
+ assertSnapshot(snapshots);
+ });
});
diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts
index 1d9b7a861e..0ece25e5d0 100644
--- a/packages/rrweb/test/utils.ts
+++ b/packages/rrweb/test/utils.ts
@@ -601,6 +601,7 @@ export function generateRecordSnippet(options: recordOptions) {
userTriggeredOnInput: ${options.userTriggeredOnInput},
maskTextFn: ${options.maskTextFn},
recordCanvas: ${options.recordCanvas},
+ recordAfter: '${options.recordAfter || 'load'}',
inlineImages: ${options.inlineImages},
plugins: ${options.plugins}
});