October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
HTML video

How to Stop Puppeteer From Downloading Videos Instead of Playing Them

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If Puppeteer downloads a video instead of showing a player, first determine what is being downloaded. It may be Chrome downloaded during Puppeteer installation, a direct media URL whose response says Content-Disposition: attachment, or a page that never embeds a <video> element. page.goto() only navigates to a URL and returns the main resource response; it is not a playback API. Inspect the final response after redirects, then inspect the page markup and media source.

1. Identify the download

There are two unrelated download paths that are often confused.

Puppeteer’s browser installation

The puppeteer package can download a compatible browser binary during installation. That happens before your script navigates anywhere. The installation guide distinguishes puppeteer-core, which does not automatically download Chrome. Changing page navigation code will not affect an installation download.

The target URL’s media response

If your script saves a file after page.goto(), or a navigation causes the browser to download a movie, inspect the target page and its network response. Page.goto() resolves with the main resource response; after redirects, that response represents the final destination.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Check the final HTTP response

Do not infer behavior from a .mp4, .webm, or other extension alone. Read the final response headers, including the response after every redirect.

Content-Disposition controls attachment behavior

MDN documents Content-Disposition: attachment as a request to download the response. inline, or no disposition header, is the browser-display path described by MDN, subject to the page context and supported media format.

Capture the headers with a command-line request:

curl -I -L "https://example.com/video"

Look at the last response in the redirect chain. A result such as:

Content-Disposition: attachment; filename="movie.mp4"
Content-Type: video/mp4

is a download response even though the MIME type identifies valid video. If you control the server, return an inline disposition (or omit the header) for a resource intended for playback. If you do not control it, Puppeteer cannot safely rewrite that server decision; use a player page that the site provides or obtain a response intended for inline display.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Verify the media type

The server must send a media type appropriate to the actual file. MDN’s video element documentation notes that web-server MIME configuration can affect handling of formats such as WebM. Correct the server’s MIME mapping and ensure the bytes match the declared type; changing only a filename is not a fix.

3. Decide whether you opened a player page or a raw file

A raw media URL is not the same thing as a webpage containing controls. A player page normally contains a <video> element and one or more sources. A direct file URL may simply return media bytes, which the browser can display in its built-in viewer only when the response is suitable for inline rendering.

Inspect the document

const videoCount = await page.$$eval('video', els => els.length);
console.log({ videoCount, url: page.url() });

const details = await page.$$eval('video', els => els.map(video => ({
  src: video.currentSrc || video.src || null,
  sources: [...video.querySelectorAll('source')].map(s => ({
    src: s.src,
    type: s.type || null
  }))
})));
console.dir(details, { depth: null });

If videoCount is zero, you navigated to a page without an embedded player. Check for an iframe, a script-created player, or a link with a download action rather than trying to change download policy.

Check for an explicit download link

An anchor such as <a href="..." download> explicitly asks the browser to download its target. MDN notes that the attribute works for same-origin URLs and blob: or data: URLs, and that headers and user settings can still influence the result. Inspect the element and the click handler before changing server configuration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const links = await page.$$eval('a[download]', els => els.map(a => ({
  href: a.href,
  download: a.getAttribute('download')
})));
console.log(links);

4. Use Puppeteer’s download settings for downloads only

Puppeteer exposes a browser-context downloadBehavior option. The ConnectOptions documentation and BrowserContextOptions documentation describe it as policy for file downloads. It can choose whether downloads are allowed and where they are written; it does not convert an attachment response into a player.

The Puppeteer files guide states: “Currently, Puppeteer does not offer a way to handle file downloads in a programmatic way.” Treat that as a boundary: configure download policy when your goal is to save a file, but fix the URL, headers, markup, or media configuration when your goal is playback.

Example diagnostic script

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();

page.on('response', async response => {
  if (response.request().isNavigationRequest()) {
    const headers = response.headers();
    console.log('final navigation', response.status(), response.url(), {
      contentType: headers['content-type'],
      contentDisposition: headers['content-disposition'] || null
    });
  }
});

await page.goto('https://example.com/player', { waitUntil: 'domcontentloaded' });
console.log('videos:', await page.$$eval('video', els => els.length));
await browser.close();

Replace the URL with the page you intend to view, not merely the media URL copied from a network panel. If the response is a redirect, the logged URL and headers describe the final navigation response.

5. Correct fixes by root cause

The script visits a raw attachment URL

Navigate to the site’s player page instead. Let that page create the <video> element and select its source. If you own the endpoint, change its response disposition to inline and serve a correct media type.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The page has no video element

There is nothing for Puppeteer to play. Use the site’s documented player route, wait for the component that creates the player, or handle the resource as a download. Do not expect page.goto() to manufacture controls.

The source is created after JavaScript runs

Wait for a selector or an application-specific readiness condition before inspecting it:

await page.goto('https://example.com/player', { waitUntil: 'networkidle2' });
await page.waitForSelector('video');
const source = await page.$eval('video', v => v.currentSrc || v.src);
console.log(source);

A delayed player is different from an attachment response. Waiting cannot override Content-Disposition: attachment.

The media type or bytes are wrong

Fix the origin server’s MIME mapping and encoding. Confirm that the declared type matches the actual container and codec supported by the browser. A WebM file served as an unrelated type can fail even when the URL looks correct.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

6. Troubleshooting checklist

  • A Chrome file appears during npm install: this is Puppeteer’s browser installation. Consider puppeteer-core only when you will provide and manage a browser executable yourself.
  • page.goto() returns a response but no player appears: log response.url(), status, Content-Disposition, and Content-Type; then count <video> elements.
  • The response has attachment: use a player URL or change the server response if you own it. Download policy cannot rewrite the header.
  • The page uses an <a download> link: inspect same-origin, blob:, or data: behavior and remove or change the link only if you control the page.
  • The player appears only after interaction: perform the required click and wait for video or the site’s ready state before reading currentSrc.
  • The video element exists but stays blank: verify the source URL, response MIME type, codec support, and whether the source itself redirects to an attachment.
  • Redirects hide the cause: inspect every hop with curl -I -L and log Puppeteer’s final response URL.

7. Or skip the browser setup

If your actual goal is a clean image or PDF of the player page rather than interactive playback, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Only clean shots are billed, while bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, with the result identified by X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

One request is enough:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for options such as full-page capture, element selectors, device presets, dark mode, custom JavaScript, waiting conditions, and PDF output. A free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

8. Cost and reliability considerations

Do not repeatedly download a large media file just to test whether a page has a player. First inspect headers and markup, then perform a full navigation only when needed. Keep browser installation separate from application runs, log final URLs after redirects, and fail clearly when the response is an attachment or when no video element exists. These checks make the automation deterministic without pretending that Puppeteer can change server-side HTTP behavior.

Frequently Asked Questions

Can a different filename extension force inline playback?

No. The browser evaluates the response headers, media type, page context, and supported format; an extension alone does not turn an attachment into a player.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What should I record when reporting this bug?

Record the Puppeteer version, browser version, original and final URLs, redirect chain, final Content-Disposition and Content-Type headers, and whether the target document contains a video element.

The Bottom Line

Separate installation downloads from page downloads, inspect the final response headers, and confirm that you opened a real player page. Use download behavior only for files; it cannot override an attachment response or create video markup.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.