{"record":{"id":"fb8fb19677613d4f","repo":"apify/crawlee","slug":"the-window-property-is-not-available-skipnavi","errorCode":null,"errorMessage":"The `window` property is not available - `skipNavigation` was used","messagePattern":"The `window` property is not available - `skipNavigation` was used","errorType":"exception","errorClass":"NavigationSkippedError","httpStatus":null,"severity":"error","filePath":"packages/jsdom-crawler/src/internals/jsdom-crawler.ts","lineNumber":365,"sourceCode":"                } catch (e) {\n                    this.log.debug((e as Error).message);\n                }\n            }\n\n            return {\n                window,\n                get body() {\n                    return window.document.documentElement.outerHTML;\n                },\n                get document() {\n                    return window.document;\n                },\n            };\n        } catch (err) {\n            if (err instanceof NavigationSkippedError) {\n                return {\n                    get window(): DOMWindow {\n                        throw new NavigationSkippedError(\n                            'The `window` property is not available - `skipNavigation` was used',\n                            { cause: err },\n                        );\n                    },\n                    get body(): string {\n                        throw new NavigationSkippedError(\n                            'The `body` property is not available - `skipNavigation` was used',\n                            { cause: err },\n                        );\n                    },\n                    get document(): Document {\n                        throw new NavigationSkippedError(\n                            'The `document` property is not available - `skipNavigation` was used',\n                            { cause: err },\n                        );\n                    },\n                };\n            }","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/jsdom-crawler/src/internals/jsdom-crawler.ts#L347-L383","documentation":"When the page handler ran with `skipNavigation: true`, the JSDOMCrawler context intentionally does not parse the response into a JSDOM window. The returned object replaces the `window` getter with one that throws NavigationSkippedError to make it obvious that DOM APIs are unavailable in skipNavigation mode.","triggerScenarios":"Using JSDOMCrawler with `skipNavigation: true` (or `skipNavigation()` in the hook flow) and then reading `context.window` in the requestHandler.","commonSituations":"Reusing a shared handler that normally parses DOM after switching some requests to skipNavigation to save resources; forgetting that skipNavigation only gives access to raw `body` bytes.","solutions":["Remove `skipNavigation: true` if you actually need DOM access.","Access `context.body` (raw response text) instead of `window` and parse manually.","Branch your handler on whether navigation was skipped before touching `window`.","Move the DOM-dependent logic to a crawler configured without skipNavigation."],"exampleFix":"// before\nasync function handler(context) {\n    const doc = context.window.document;\n}\n\n// after with skipNavigation\nasync function handler(context) {\n    const html = context.body; // raw string, no JSDOM window\n    const $ = (await import('cheerio')).load(html);\n}","handlingStrategy":"try-catch","validationCode":"const navigationSkipped = request.skipNavigation === true;\nif (navigationSkipped) {\n    // do not touch context.window\n}","typeGuard":"function isNavigationSkippedError(err: unknown): err is Error & { name: 'NavigationSkippedError' } {\n    return err instanceof Error && err.name === 'NavigationSkippedError';\n}","tryCatchPattern":"try {\n    const { window } = context;\n    process(window);\n} catch (err) {\n    if ((err as Error).message.includes('`skipNavigation` was used')) {\n        return handleRawBody(context.body);\n    }\n    throw err;\n}","preventionTips":["Keep two handler variants: one for skipNavigation requests, one for DOM parsing.","Never share DOM-accessing handler code with skipNavigation-enabled crawlers without a guard.","Encode skipNavigation in request userData and branch on it at handler start.","Add an integration test covering a skipNavigation request through your handler."],"tags":["jsdom","skip-navigation","dom","api-misuse"],"backgroundTag":"dom-unavailable-skip-navigation","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}