1"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[25316],{20067:(e,s,r)=>{r.d(s,{A:()=>n});const n=r.p+"assets/images/screencast-43f96abae5f3a3ab641e14f36f05d9a5.gif"},22002:(e,s,r)=>{r.d(s,{R:()=>d,x:()=>o});var n=r(7378);const i={},t=n.createContext(i);function d(e){const s=n.useContext(t);return n.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function o(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(t.Provider,{value:s},e.children)}},22408:(e,s,r)=>{r.r(s),r.d(s,{assets:()=>c,contentTitle:()=>o,default:()=>a,frontMatter:()=>d,metadata:()=>n,toc:()=>l});const n=JSON.parse('{"id":"devtools/wdio/screencast","title":"Session Screencast","description":"Records browser sessions as .webm videos. Videos are displayed in the DevTools UI alongside the snapshot and DOM mutation views.","source":"@site/docs/devtools/wdio/Screencast.md","sourceDirName":"devtools/wdio","slug":"/devtools/wdio/screencast","permalink":"/docs/devtools/wdio/screencast","draft":false,"unlisted":false,"editUrl":"https://github.com/webdriverio/webdriverio/edit/main/website/docs/devtools/wdio/Screencast.md","tags":[],"version":"current","frontMatter":{"id":"screencast","t
1itle":"Session Screencast"},"sidebar":"docs","previous":{"title":"Multi-Framework Support","permalink":"/docs/devtools/wdio/multi-framework-support"},"next":{"title":"Trace Mode","permalink":"/docs/devtools/wdio/trace-mode"}}');var i=r(86106),t=r(22002);const d={id:"screencast",title:"Session Screencast"},o=void 0,c={},l=[{value:"Demo",id:"demo",level:2},{value:"Setup",id:"setup",level:2},{value:"Configuration",id:"configuration",level:2},{value:"Options",id:"options",level:2},{value:"Browser Support",id:"browser-support",level:2},{value:"Behaviour",id:"behaviour",level:2},{value:"Where output files land",id:"where-output-files-land",level:3},{value:"Output Files",id:"output-files",level:2}];function h(e){const s={a:"a",code:"code",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(s.p,{children:["Records browser sessions as ",(0,i.jsx)(s.code,{children:".webm"})," videos. Videos are displayed in the DevTools UI alongside the snapshot and DOM mutation views."]}),"\n",(0,i.jsxs)(s.p,{children:["Available across all three adapters - ",(0,i.jsx)(s.strong,{children:"WebdriverIO"}),", ",(0,i.jsx)(s.strong,{children:(0,i.jsx)(s.a,{href:"/docs/devtools/selenium",children:"Selenium WebDriver"})}),", and ",(0,i.jsx)(s.strong,{children:(0,i.jsx)(s.a,{href:"/docs/devtools/nightwatch#screencast",children:"Nightwatch.js"})}),". The capture mode differs per framework (CDP push where possible, polling otherwise - see ",(0,i.jsx)(s.a,{href:"#browser-support",children:"Browser Support"})," below)."]}),"\n",(0,i.jsx)(s.h2,{id:"demo",children:"Demo"}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Screencast Demo",src:r(20067).A+"",width:"800",height:"497"})}),"\n",(0,i.jsx)(s.h2,{id:"setup",children:"Setup"}),"\n",(0,i.jsxs)(s.p,{children:["Screencast encoding requires ",(0,i.jsx)(s.strong,{children:"ffmpeg"})," on ",(0,i.jsx)(s.code,{children:"PATH"})," and the ",(0,i.jsx)(s.code,{children:"fluent-ffmpeg"})," package:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-sh",children:"# Install ffmpeg - https://ffmpeg.org/download.html\nbrew install ffmpeg # macOS\nsudo apt install ffmpeg # Ubuntu/Debian\n\n# Install fluent-ffmpeg\nnpm install fluent-ffmpeg\n"})}),"\n",(0,i.jsx)(s.h2,{id:"configuration",children:"Configuration"}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-ts",children:"services: [\n [\n 'devtools',\n {\n screencast: {\n enabled: true,\n captureFormat: 'jpeg',\n quality: 70,\n maxWidth: 1280,\n maxHeight: 720,\n }\n }\n ]\n]\n"})}),"\n",(0,i.jsx)(s.h2,{id:"options",children:"Options"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Option"}),(0,i.jsx)(s.th,{children:"Type"}),(0,i.jsx)(s.th,{children:"Default"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"enabled"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"boolean"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"false"})}),(0,i.jsx)(s.td,{children:"Enable session recording"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"captureFormat"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"'jpeg' | 'png'"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"'jpeg'"})}),(0,i.jsxs)(s.td,{children:["Frame image format. ",(0,i.jsx)(s.strong,{children:"Chrome/Chromium only"})," - controls the format Chrome sends over CDP. Ignored in polling mode (Firefox, Safari) where screenshots are always PNG. Does not affect the output video container, which is always ",(0,i.jsx)(s.code,{children:".webm"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"quality"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"number"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"70"})}),(0,i.jsxs)(s.td,{children:["JPEG compression quality 0-100. Only applies in Chrome/Chromium CDP mode with ",(0,i.jsx)(s.code,{children:"captureFormat: 'jpeg'"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"maxWidth"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"number"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"1280"})}),(0,i.jsxs)(s.td,{children:["Maximum frame width in pixels. ",(0,i.jsx)(s.strong,{children:"Chrome/Chromium only"})," - Chrome scales frames before sending over CDP. Ignored in polling mode"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"maxHeight"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"number"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"720"})}),(0,i.jsxs)(s.td,{children:["Maximum frame height in pixels. ",(0,i.jsx)(s.strong,{children:"Chrome/Chromium only"})," - same as above"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"pollIntervalMs"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"number"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"200"})}),(0,i.jsx)(s.td,{children:"Screenshot interval in milliseconds for non-Chrome browsers (polling mode). Lower = smoother video but more WebDriver round-trips during test execution"})]})]})]}),"\n",(0,i.jsx)(s.h2,{id:"browser-support",children:"Browser Support"}),"\n",(0,i.jsx)(s.p,{children:"Recording works across all major browsers using automatic mode selection:"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Browser"}),(0,i.jsx)(s.th,{children:"Mode"}),(0,i.jsx)(s.th,{children:"Notes"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Chrome / Chromium / Edge"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"CDP push"})}),(0,i.jsx)(s.td,{children:"Chrome pushes frames over the DevTools Protocol. Efficient - no impact on test c
1ommand timing"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Firefox / Safari / others"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"BiDi polling"})}),(0,i.jsxs)(s.td,{children:["Falls back to calling ",(0,i.jsx)(s.code,{children:"browser.takeScreenshot()"})," at ",(0,i.jsx)(s.code,{children:"pollIntervalMs"})," intervals. Works wherever WebDriver screenshots are supported; adds a small overhead proportional to the interval"]})]})]})]}),"\n",(0,i.jsx)(s.p,{children:"No configuration change is needed to switch modes - the service detects browser capabilities automatically and logs which mode is active."}),"\n",(0,i.jsx)(s.h2,{id:"behaviour",children:"Behaviour"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsx)(s.li,{children:"Recording starts when the browser session opens and stops when it closes."}),"\n",(0,i.jsx)(s.li,{children:"Leading blank frames (captured before the first URL navigation) are automatically trimmed so videos begin at the first meaningful page action."}),"\n",(0,i.jsxs)(s.li,{children:["If ",(0,i.jsx)(s.code,{children:"browser.reloadSession()"})," is called mid-run, the service finalises the current recording and starts a fresh one for the new session. Each session produces its own ",(0,i.jsx)(s.code,{children:".webm"})," file."]}),"\n",(0,i.jsxs)(s.li,{children:["When multiple recordings exist, the DevTools UI shows a ",(0,i.jsx)(s.strong,{children:"Recording N"})," dropdown to switch between them."]}),"\n"]}),"\n",(0,i.jsx)(s.h3,{id:"where-output-files-land",children:"Where output files land"}),"\n",(0,i.jsxs)(s.p,{children:["The directory each adapter picks is slightly different - they all share the same resolver in ",(0,i.jsx)(s.code,{children:"@wdio/devtools-core"})," but feed it different inputs:"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Adapter"}),(0,i.jsx)(s.th,{children:"Output location"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"WebdriverIO"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"outputDir"})," if explicitly set in ",(0,i.jsx)(s.code,{children:"wdio.conf.ts"}),", otherwise ",(0,i.jsx)(s.code,{children:"rootDir"})," (the dir containing the config). Avoid setting ",(0,i.jsx)(s.code,{children:"outputDir"})," just to control video paths - WDIO redirects worker logs there too."]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Selenium"})}),(0,i.jsxs)(s.td,{children:["Directory of the test file that just ran, falling back to ",(0,i.jsx)(s.code,{children:"process.cwd()"}),"."]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Nightwatch"})}),(0,i.jsxs)(s.td,{children:["Directory of the test file, falling back to the directory containing ",(0,i.jsx)(s.code,{children:"nightwatch.conf.*"}),", then ",(0,i.jsx)(s.code,{children:"process.cwd()"}),"."]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Directories under ",(0,i.jsx)(s.code,{children:"node_modules/"})," are skipped on the Selenium/Nightwatch path so symlinked workspaces don't dump videos into a dependency folder."]}),"\n",(0,i.jsx)(s.h2,{id:"output-files",children:"Output Files"}),"\n",(0,i.jsxs)(s.p,{children:["Live mode streams captured data to the dashboard over WebSocket and writes ",(0,i.jsx)(s.strong,{children:"no trace file to disk"})," \u2014 for a portable artifact, use ",(0,i.jsx)(s.a,{href:"/docs/devtools/wdio/trace-mode",children:"trace mode"})," (",(0,i.jsx)(s.code,{children:"trace.zip"}),"). The only file live mode writes is the screencast video, and only when ",(0,i.jsx)(s.code,{children:"screencast.enabled: true"}),". Filenames are adapter-specific (the framework name appears in the prefix):"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Adapter"}),(0,i.jsx)(s.th,{children:"Screencast video"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"WebdriverIO"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"wdio-video-{sessionId}.webm"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Selenium"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"selenium-video-{sessionId}.webm"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Nightwatch"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"nightwatch-video-{sessionId}.webm"})})]})]})]})]})}function a(e={}){const{wrapper:s}={...(0,t.R)(),...e.components};return s?(0,i.jsx)(s,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.