Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Set the download name in the HTTP response, not by assuming every export API accepts a filename request parameter. Return the file with Content-Disposition: attachment and a suitable filename; add UTF-8 filename* when names contain non-ASCII characters. Treat the result as a suggestion: browsers and programs can change it, and clients must sanitize it before writing to disk.
The interoperable way to name an API download
For a response intended to be saved, send the media type and a Content-Disposition header together:
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
(binary PDF bytes)
attachment tells user agents to use a download/save workflow. The filename parameter suggests the local name. It does not rename a file on the server and it does not force every client to use that exact text. RFC 6266 describes the filename as advisory information and warns recipients to handle it carefully (RFC 6266).
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchQuote names containing spaces or characters that cannot appear in a token:
#1 Best Overall
Content-Disposition: attachment; filename="Q4 sales report.pdf"
Keep the extension consistent with the bytes you return. A PDF response called report.csv may open incorrectly or trigger a misleading warning.
Unicode filenames and compatibility fallbacks
For names such as résumé.pdf, use the extended filename* parameter with UTF-8 and percent encoding. Include an ASCII fallback for clients that do not implement the extended form:
Content-Disposition: attachment; filename="resume.pdf"; filename*=UTF-8''r%C3%A9sum%C3%A9.pdf
RFC 6266 recommends placing the ordinary filename first when both are present because some parsers mishandle parameter order. A client that understands filename* should prefer it. Do not put percent escapes in the ordinary filename and expect consistent decoding: MDN documents different browser behavior (MDN Content-Disposition reference).
Generate the extended value with a standards-compliant URL-encoding routine, while keeping the fallback readable ASCII. Avoid backslashes in quoted values and remove control characters before constructing either parameter.
Server-side implementation patterns
Node.js without a framework
This example streams a generated PDF and supplies both forms of the name. In production, use a vetted content-disposition library or carefully test your encoder against your supported clients.
Rank #2
- Used Book in Good Condition
import http from 'node:http';
const server = http.createServer(async (req, res) => {
if (req.url !== '/export') {
res.writeHead(404).end('Not found');
return;
}
const bytes = await createPdf(); // return a Buffer
const fallback = 'resume.pdf';
const utf8Name = encodeURIComponent('résumé.pdf');
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Length': bytes.length,
'Content-Disposition': `attachment; filename="${fallback}"; filename*=UTF-8''${utf8Name}`
});
res.end(bytes);
});
server.listen(3000);
Never interpolate an untrusted string directly into a header. Remove CR, LF, quotes and path separators, restrict length, and choose an extension from the actual output format.
Express 4.x
Express exposes a higher-level helper:
app.get('/export', (req, res, next) => {
const absolutePath = '/srv/exports/report.pdf';
res.download(absolutePath, 'Q4 sales report.pdf', err => {
if (err) next(err);
});
});
In Express 4.x, the optional second argument overrides the name derived from the path and sends the file as an attachment (Express response API). If a user can influence the path, constrain it with a trusted root or map an identifier to a server-side path; do not concatenate arbitrary path text.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesPython (Flask-style response)
from flask import Flask, Response
from urllib.parse import quote
app = Flask(__name__)
@app.get('/export')
def export_file():
data = build_pdf() # bytes
fallback = 'resume.pdf'
encoded = quote('résumé.pdf', safe="")
disposition = (
f'attachment; filename="{fallback}"; '
f"filename*=UTF-8''{encoded}"
)
return Response(data, mimetype='application/pdf', headers={
'Content-Disposition': disposition
})
For large exports, stream the response instead of holding all bytes in memory. Ensure the streaming layer preserves your headers.
Request parameters versus response headers
Some vendors expose a product-specific option such as reportName; others derive a name from an object ID or source path. There is no universal request field called filename. Check the endpoint’s documentation before sending one.
Carbone generated reports
Carbone accepts reportName as a static value or dynamic template tags. It returns that name through Content-Disposition and appends the output extension for the generated format (Carbone generate reports). Supply a base name, not a second extension, when Carbone is responsible for adding it.
Rank #3
Google Drive downloads and exports
Google Drive has separate operations for binary blobs and Workspace documents. The guide distinguishes files.get with alt=media from files.export, along with browser and long-running-operation paths. Check capabilities.canDownload before attempting either operation; do not assume one filename option applies to every path (Google Drive download and export guide).
Browser downloads and programmatic clients are different
A browser may honor the header when navigating to an attachment response, but a script that receives bytes can choose any local name. For example, Python’s requests library does not automatically create a file with the server’s suggested name; your code must parse the header or select its own name.
import requests
r = requests.get('https://api.example.com/export', timeout=90)
r.raise_for_status()
with open('chosen-name.pdf', 'wb') as f:
f.write(r.content)
If you want to honor a server suggestion, parse Content-Disposition with a standards-aware parser, then sanitize the resulting basename. Never treat it as a trusted path.
For same-origin links, MDN notes that Chrome and Firefox 82 and later can prioritize an anchor’s download attribute over Content-Disposition: inline. That browser-specific interaction does not override a server response marked attachment, and it does not control programmatic clients.
Filename safety checklist
- Discard directory components such as
../, backslashes and drive prefixes; keep only a basename. - Reject or replace control characters, including CR and LF, to prevent header injection.
- Normalize or replace characters your target filesystem cannot store.
- Trim leading and trailing whitespace and handle reserved names such as device filenames on Windows.
- Do not allow a dangerous extension to be selected merely because a user supplied it; derive the extension from the generated media type.
- Limit length and provide a deterministic fallback when the cleaned name is empty.
- Prevent accidental overwrites by choosing a unique destination or asking the user before replacing an existing file.
- Do not execute downloaded content solely because its suggested name has an executable extension.
These precautions apply on both sides: the API should emit a safe suggestion, and the receiving application should still validate it. RFC 6266 specifically warns that recipients must not allow a server-provided name to write outside an authorized location.
Recommended Free Tools
Rank #4
Diagnosing a wrong or missing filename
The browser uses an unexpected name
Inspect the actual response with your browser’s network panel or curl -I. Confirm that the final response, after redirects, contains Content-Disposition. A proxy, CDN or framework middleware may replace it. Check for duplicate headers and verify that the response is the file bytes rather than an HTML error page.
The name is truncated or garbled
Use a quoted ASCII fallback plus UTF-8 filename*. Confirm that the extended value is percent-encoded and that the fallback appears first. Test the browsers and operating systems you support; clients do not interpret malformed parameters identically.
The downloaded file has no extension
Verify that your header includes the extension and that the media type matches it. If a vendor appends an extension automatically, remove the duplicate extension from your supplied base name.
A script saves the wrong name
Remember that a programmatic client controls its own destination. Parse the header explicitly or set the local name in your file-writing code. Follow redirects and inspect the final response headers.
The request succeeds but no file is offered
Check whether the endpoint returns inline, JSON metadata, a permission error or an asynchronous job result instead of the file. For Google Drive, verify download/export capability before requesting media.
Best Value
Performance, reliability and caching considerations
Filename headers add negligible response overhead; generation and transfer time dominate. For large files, stream bytes and send an accurate Content-Length when known. If exports are asynchronous, return a job status first and apply the final filename on the URL that serves the completed artifact.
Test through every layer that can alter headers: application middleware, reverse proxies, object storage, signed URLs and download accelerators. Preserve Content-Disposition when forwarding the response. Log the selected safe basename, not untrusted raw input, and avoid putting sensitive data in names that appear in browser history or proxy logs.
Or skip the browser setup
If your export is a website screenshot, ScreenshotNeo returns the image or PDF directly from one API call. You can choose your own output filename when writing the response locally:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the complete options in the ScreenshotNeo documentation. It removes cookie banners, newsletter popups and chat widgets before capture; bot checks, blank pages and failed loads are not billed. Its MCP server lets AI agents take screenshots, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.
FAQ
Can I set a download filename in a GET query string?
Only when that particular API documents such a parameter. Otherwise, set the response header or choose the name in your client.
Should I send only filename*?
For broad compatibility, send an ASCII filename fallback first and the UTF-8 filename* value second.
Does Content-Disposition rename the server’s stored file?
No. It suggests a name to the recipient for this response; storage naming is a separate concern.
Frequently Asked Questions
Can a CDN change my filename header?
Yes. Inspect the final response after redirects and verify proxy or object-storage rules preserve Content-Disposition.
What if my export is a ZIP or spreadsheet instead of a PDF?
Use the media type and extension that match the actual bytes, while applying the same attachment, fallback, Unicode and sanitization rules.
Quick Recap
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.

