Download Control#

Use the dl parameter to control the download behavior of images. You can choose whether the browser displays or downloads the image.

Usage#

ParameterBehaviorDescription
(no parameter)inline

Display image in browser (default behavior)

transform=dlattachment

Download with original filename

transform=dl:custom-nameattachment

Download with custom filename (extension automatically adjusted to match converted format)

Examples#

Display in browser (default behavior)

https://cdn.snapkit.studio/org/project/image.jpg

Download with original filename

https://cdn.snapkit.studio/org/project/image.jpg?transform=dl

Download with custom filename

https://cdn.snapkit.studio/org/project/image.jpg?transform=dl:my-photo

The extension is automatically adjusted to match the converted format. For example, an image converted to WebP will be downloaded as my-photo.webp.

Combined with transformations

https://cdn.snapkit.studio/org/project/image.jpg?transform=w:800,format:webp,dl:optimized-image

This example resizes the image to 800px width, converts it to WebP format, and downloads it as optimized-image.webp.

Security & Standards Compliance#

  • Path Traversal Prevention: Automatically removes .. and path separators
  • XSS Prevention: Filters dangerous characters (<>:"|?* and control characters)
  • Filename Length Limit: Maximum 255 characters
  • RFC 5987/6266 Compliance: Safely handles international characters (Korean, Japanese, etc.)
  • UTF-8 Encoding: Ensures correct filename display across all browsers

JavaScript/TypeScript Example#

// Create download URL
const createDownloadUrl = (imageUrl: string, filename?: string) => {
  const url = new URL(imageUrl);
  const existingTransform = url.searchParams.get('transform') || '';
  const dlParam = filename ? `dl:${filename}` : 'dl';
 
  // Append to existing transform or create new
  const newTransform = existingTransform
    ? `${existingTransform},${dlParam}`
    : dlParam;
 
  url.searchParams.set('transform', newTransform);
  return url.toString();
};
 
// Usage examples
const imageUrl = 'https://cdn.snapkit.studio/org/project/image.jpg';
 
// Download with original filename
const downloadOriginal = createDownloadUrl(imageUrl);
// → https://cdn.snapkit.studio/org/project/image.jpg?transform=dl
 
// Download with custom filename
const downloadCustom = createDownloadUrl(imageUrl, 'my-photo');
// → https://cdn.snapkit.studio/org/project/image.jpg?transform=dl:my-photo
 
// Combined with transformations
const imageWithTransform = 'https://cdn.snapkit.studio/org/project/image.jpg?transform=w:800,format:webp';
const downloadTransformed = createDownloadUrl(imageWithTransform, 'optimized');
// → https://cdn.snapkit.studio/org/project/image.jpg?transform=w:800,format:webp,dl:optimized

Download Methods Comparison: <a download> vs Server-Side Control#

There are two main ways to control image downloads:

  1. Client-side: HTML <a download> attribute
  2. Server-side: Content-Disposition header (Snapkit's dl parameter)

Each approach is needed for different situations, and sometimes they're used together.

Feature Comparison#

Feature<a download>dl Parameter (Server-side)
Applies toHTML link clicks onlyAll HTTP requests
CORS Restrictions❌ Blocked for cross-origin✅ Works cross-origin
JavaScript fetch❌ Not applicable✅ Works
Direct URL access❌ Displays in browser✅ Downloads
Mobile apps❌ Not available✅ Available
API requests❌ Not available✅ Available

When <a download> is Appropriate#

Simple downloads from same domain

<!-- ✅ Works well for same-origin resources -->
<a href="/uploads/document.pdf" download="my-document.pdf">
  Download Document
</a>

Dynamic filename control on client

const handleDownload = (filename: string) => {
  const link = document.createElement('a');
  link.href = '/api/file/123';
  link.download = `${filename}-${Date.now()}.pdf`;
  link.click();
};

When dl Parameter (Server-side) is Required#

1. CDN/Cross-origin Downloads (Required)

// ❌ Blocked by CORS with <a download>
<a href="https://cdn.snapkit.studio/org/image.jpg" download="my-photo.jpg">
  Download (doesn't work - cross-origin)
</a>
 
// ✅ Server-side dl parameter required
<a href="https://cdn.snapkit.studio/org/image.jpg?transform=dl:my-photo">
  Download (works correctly)
</a>

2. JavaScript fetch/API Requests

// ✅ Handle downloads with fetch
const response = await fetch(
  'https://cdn.snapkit.studio/org/image.jpg?transform=dl:photo'
);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.click();

3. Direct URL Access Auto-download

When users enter URL directly in browser:

https://cdn.snapkit.studio/org/image.jpg?transform=dl
→ Automatically downloads instead of displaying in browser

4. Display or Download Same Image

<!-- Display in browser -->
<img src="https://cdn.snapkit.studio/org/image.jpg" />
 
<!-- Download same image -->
<a href="https://cdn.snapkit.studio/org/image.jpg?transform=dl">
  Download
</a>

Recommendations#

When using Snapkit:

  • Use dl parameter since CDN is on a different domain
  • <a download> can be used supplementarily, but won't work cross-origin
  • dl parameter is required for API integration or fetch usage

Example combining both approaches:

<!-- Server-side control + client-side filename hint -->
<a
  href="https://cdn.snapkit.studio/org/image.jpg?transform=dl:photo"
  download="my-custom-photo.jpg"
>
  Download
</a>

The server's Content-Disposition header takes precedence, with the download attribute acting as a fallback.

Next Steps#