@browserless/capture
v13.4.0
Published
Record a Puppeteer page using tabCapture API
Maintainers
Readme
@browserless/capture: Record a Puppeteer page using tabCapture API.
Install
npm install @browserless/capture --saveUsage
const createBrowser = require('browserless')
const createCapture = require('@browserless/capture')
const withCaptureExtension = (launchOpts = {}) => {
const ignoreDefaultArgs = launchOpts.ignoreDefaultArgs
return {
...launchOpts,
args: [
...(launchOpts.args || []),
`--allowlisted-extension-id=${createCapture.extensionId}`,
`--disable-extensions-except=${createCapture.extensionPath}`,
`--load-extension=${createCapture.extensionPath}`
],
ignoreDefaultArgs:
ignoreDefaultArgs === true
? true
: [
...new Set([
...(Array.isArray(ignoreDefaultArgs) ? ignoreDefaultArgs : []),
'--disable-extensions'
])
]
}
}
const browser = createBrowser(withCaptureExtension({ headless: 'new' }))
const browserless = await browser.createContext()
const puppeteerBrowser = await browserless.browser()
const page = await puppeteerBrowser.defaultBrowserContext().newPage()
const capture = createCapture({ goto: browserless.goto })
const video = await capture(page)('https://example.com', {
duration: 5000,
type: 'mp4',
codec: 'avc1.4D401F',
path: '/tmp/demo.mp4'
})
await page.close()
await browserless.destroyContext()
await browser.close()browserless core does not inject capture extension flags automatically.
@browserless/capture requires:
- Loading the bundled extension using
--allowlisted-extension-id,--disable-extensions-except, and--load-extension. - Ensuring Chromium default arg
--disable-extensionsis ignored. - Creating the captured page from
defaultBrowserContext()(not an incognito context).
API shape is intentionally simple, similar to page.screenshot()/page.pdf():
const capture = createCapture({ goto })
await capture(page)(url, opts)Returns a Buffer and writes to opts.path when provided.
Options
The capture mode is selected by entry point, not by an option.
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| type | 'webm' \| 'mp4' | 'mp4' | Output type selector mapped to MediaRecorder mime type. |
| codec | string | Depends on type | MediaRecorder codec override. Defaults: webm -> vp9, mp4 -> avc1.4D401F. |
| path | string | undefined | Write the captured media to disk. |
| duration | number | 5000 | Capture duration in milliseconds. |
| audio | boolean \| object | false | Capture audio. When object, it is used as audio track constraints. |
| video | boolean \| object | true | Capture video. When object, it is used as video track constraints. |
Modes
Each capture mode is a separate entry point, so you pull in only what you use
(e.g. the extension mode doesn't load the ffmpeg-based deps):
const createCapture = require('@browserless/capture') // extension (default)
const createCapture = require('@browserless/capture/screencast')
const createCapture = require('@browserless/capture/screenshot')All three share the same factory signature — createCapture({ goto })(page)(url, opts).
| Entry point | How | Notes |
| --- | --- | --- |
| @browserless/capture (/extension) | In-browser MediaRecorder via the bundled extension (tabCapture). | Default. Device-pixel (retina) output. Captures audio. |
| @browserless/capture/screencast | CDP Page.startScreencast frames muxed into ffmpeg. | Video-only (video: false throws). CSS-pixel output. Requires ffmpeg. |
| @browserless/capture/screenshot | Polled page.screenshot frames muxed into ffmpeg. | Video-only. The only mode that captures accelerated layers (WebGL/canvas/video). Device-pixel output, bounded by screenshot latency. Requires ffmpeg. |
Exports
capture.extensionPath: Absolute path to the bundled extension.capture.extensionId: Extension ID used by the package.capture.MODES: Names of the available capture modes (entry points).capture.types: Supported values fortype.captureusesgoto(...).device.viewportas the capture viewport source. Whenvideoistrueor omitted, video constraints are inferred from that viewport to keep capture framing aligned with screenshot/pdf rendering. Whenvideois an object, that object is used as the video constraints. Whenaudiois an object, that object is used as the audio constraints. The inferred constraints also account fordeviceScaleFactor, so output video pixels match screenshot pixel density.typeis mapped internally to the MediaRecorder mime type, andcodecis appended as;codecs=.... Default codecs arevp9forwebmandavc1.4D401Fformp4. You can override codec per request usingopts.codec. For example:
await capture(page)(url, { type: 'webm', codec: 'vp8' })
await capture(page)(url, { type: 'mp4', codec: 'avc1.640033' })When type is 'mp4', the running Chromium build must support MP4 MediaRecorder output.
For strict screenshot/poster parity in headless mode, launch Chrome with matching --screen-info.
License
@browserless/capture © Microlink, released under the MIT License.
