Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.zenrows.com/llms.txt

Use this file to discover all available pages before exploring further.

ZenRows lets you download images, PDFs, and other binary files directly from web pages as part of your scraping workflow. Instead of scraping HTML and then fetching assets separately, you can point the API at a file URL and receive the binary content ready to save. This is useful for collecting product images, downloadable reports, manuals, or any non-text content that lives at a direct URL.

How it works

There are two scenarios where ZenRows can return a file download:
1

Direct file response

If the target URL returns the file directly in the HTTP response (for example, a direct link to a PDF or image), ZenRows fetches the file and returns it as binary content. This is the most reliable and straightforward method.
2

Triggered download via JS Instructions

If the download is triggered by a user action (such as clicking a button or link), you can use ZenRows JS Instructions to simulate that interaction. If the file download starts automatically after the action without prompting the user to choose a save location, ZenRows can capture and return the file.
Find more details on our JS Instructions Documentation.
Downloads are only possible when the file is delivered directly in the HTTP response. If the site asks the user to choose a download location or requires additional interaction after the trigger, ZenRows cannot capture the file. In those cases, use the Scraping Browser for more control over the browser session.

Basic usage

Pass the direct file URL as the url parameter. ZenRows returns the binary content of the file, which you can then save to disk:
import requests

apikey = "YOUR_ZENROWS_API_KEY"
target_url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"

params = {
    "url": target_url,
    "apikey": apikey,
}

response = requests.get("https://api.zenrows.com/v1/", params=params)

if response.status_code == 200:
    with open("output.pdf", "wb") as f:
        f.write(response.content)
    print("File downloaded and saved to output.pdf")
else:
    print(f"Download failed. Status: {response.status_code}")
Always save the response as binary. Use response.content in Python (not response.text) and binary write mode ("wb") when opening the output file. Writing binary content as text will corrupt the file.

When to use file downloads

File download is the right approach when the content you need is a binary asset rather than scraped HTML. It works well for:
  • Product images: download images directly from e-commerce product pages or media libraries.
  • PDFs and documents: collect downloadable reports, whitepapers, manuals, or invoices.
  • Data exports: fetch CSV, JSON, or XML files served at direct URLs.
  • Media assets: download audio or video files linked directly on a page.
For files that require navigating a page and triggering a download interaction, use JS Instructions to simulate the user action before the file is returned.

File size limits

ZenRows enforces a maximum file size per request to ensure stable performance across all plans. If the file you are trying to download exceeds your plan’s limit, the API returns a 413 Content Too Large error.
You can find the file size limits for each plan on our Pricing Documentation.

Best practices

Save as binary, not text:
All file downloads return binary content. Always write the response body in binary mode (for example, "wb" mode in Python and Ruby, Buffer in Node.js, or FileOutputStream in Java). Writing binary content as text will produce a corrupt file.
Enable js_render for pages that load content dynamically:
If the page loads content dynamically after the initial render, enable js_render to ensure the full page is visible before the file is downloaded.
Find more details on our JS Rendering Documentation.
Enable premium_proxy for pages that are blocked by anti-bot systems:
If the page is blocked by an anti-bot system, enable premium_proxy to bypass the block.
Find more details on our Premium Proxy Documentation.
Check the status code before saving:
Always verify that the response returned a 200 status code before writing to disk. Saving an error response as a file will produce an unreadable or corrupt output.
Use direct file URLs where possible:
Direct file URLs (ending in .pdf, .jpg, .csv, etc.) are the most reliable download method. If you need to navigate to a page first to trigger the download, use JS Instructions to simulate the click and capture the resulting file.
Credits are charged on successful responses:
File download requests are charged when the API returns a 200 status code, regardless of what the file contains. Test with a small set of URLs before running large download batches.

Troubleshooting

You are likely writing the response as text instead of binary. Make sure you are using binary write mode in your language of choice ("wb" in Python and Ruby, Buffer in Node.js, FileOutputStream in Java) and writing the raw response body rather than a text representation of it. This applies to all binary file types including PDFs, images, and archives.
This usually means the target URL returns a webpage rather than the file directly. Check that the URL you are passing points directly to the file (for example, ending in .pdf or .jpg) rather than to a page that contains a download button or link. For page-triggered downloads, use JS Instructions to simulate the interaction.
The file exceeds your plan’s maximum file size limit. Check the Pricing Documentation for the limit on your plan. For large files, consider whether you can access a compressed version or a lower-resolution asset from the same source.
If the file download is initiated by a user action (a button or link click), you need to use JS Instructions to simulate that interaction. If the download then prompts the user to choose a save location or requires additional confirmation, ZenRows cannot capture it. In that case, use the Scraping Browser for full browser session control.

Pricing

File download requests are included at no additional cost with all ZenRows requests. You only pay extra for JS Render and Premium Proxy when used.
You can monitor your ZenRows usage in multiple ways to stay informed about your account activity and prevent unexpected overages.Dashboard monitoring: View real-time usage statistics, remaining requests, success rates, and request history on your Analytics Page. You can also set up usage alerts in your notification settings to receive notifications when you approach your limits.Programmatic monitoring: For automated monitoring in your applications, call the /v1/subscriptions/self/details endpoint with your API key in the X-API-Key header. This returns real-time usage data that you can integrate into your monitoring systems. Learn more about the usage endpoint.Response header monitoring: Track your concurrency usage through response headers included with each request:
  • Concurrency-Limit: Your maximum concurrent requests
  • Concurrency-Remaining: Available concurrent request slots
  • X-Request-Cost: Cost of the current request

FAQ (Frequently Asked Questions)

ZenRows can download any file type that is returned directly in the HTTP response body, including PDFs, images (PNG, JPEG, WebP, GIF), CSVs, ZIPs, audio files, and video files. The API returns the raw binary content regardless of file type.
No, not for direct file URLs. If the URL points directly to a file, ZenRows fetches and returns it without needing a browser render. You only need js_render=true if the file download is triggered by a JavaScript interaction on a page.
No. Each ZenRows request targets a single URL and returns a single response. To download multiple files, send a separate request for each file URL. For high-volume downloads, use concurrent requests within your plan’s concurrency limits.
Yes. You can pass custom headers (such as Authorization or session cookies) using the custom_headers parameter to authenticate with the target server before the file is returned. Another method is to use the JS Instructions to simulate the user action that triggers the download.
Find more details on our JS Instructions Documentation.
The API returns a 413 Content Too Large error. The request is still counted toward your usage. Check your plan’s file size limit in the Pricing Documentation before downloading large files at scale.