Responsive Card Images
Learn how to implement responsive card images using the Card Images API's automatic thumbnail generation system. This guide covers modern responsive image techniques including srcset, sizes, the <picture> element, and lazy loading for optimal performance across all devices.
Overview
The Card Images API automatically generates three optimized thumbnail variants for every uploaded image, enabling you to deliver the perfect image size for each device and viewport. This ensures:
- Fast page loads - Smaller images for mobile devices
- Sharp displays - High-resolution images for retina screens
- Bandwidth savings - Users only download what they need
- Better UX - Instant loading with lazy loading techniques
Automatic Thumbnail Generation
When you upload a card image, the API automatically creates three thumbnail variants in addition to the original:
| Variant | Width | Quality | Use Case |
|---|---|---|---|
| small | 150px | 75% | Mobile lists, thumbnails, low-bandwidth |
| medium | 300px | 80% | Tablet views, standard displays |
| large | 600px | 85% | Desktop views, retina mobile |
| original | As uploaded | 100% | Full-screen, zoom, high-res displays |
Key Features
- Async generation - Thumbnails are created in the background via queued jobs
- Aspect ratio preserved - All variants maintain the original aspect ratio
- JPEG format - All images are converted to optimized JPEG
- CDN ready - URLs redirect to CDN for fast global delivery
Thumbnails are generated asynchronously. If a variant isn't ready yet, the download endpoint returns the original image. For production apps, consider polling or showing a loading state.
Requesting Image Sizes
Use the size parameter on the download endpoint to request specific variants:
# Get small thumbnail (150px)
GET /v1/card-images/{id}/download?size=small
# Get medium thumbnail (300px)
GET /v1/card-images/{id}/download?size=medium
# Get large thumbnail (600px)
GET /v1/card-images/{id}/download?size=large
# Get original image (no size parameter)
GET /v1/card-images/{id}/download
Versioned CDN URLs
All card images are delivered via DigitalOcean Spaces CDN with automatic versioned URLs for cache invalidation. When you fetch image metadata, the API returns CDN URLs with version parameters:
{
"data": {
"attributes": {
"download_url": "https://cdn.tradingcardapi.com/cards/.../image.jpg?v=1699564800",
"variants": {
"small": {
"url": "https://cdn.tradingcardapi.com/cards/.../image_small.jpg?v=1699564800"
}
}
}
}
}
The ?v=1699564800 version parameter is automatically updated when the image changes, ensuring browsers and CDN always serve the latest version without manual cache purging. See the CDN Integration guide for details.
Instead of constructing download endpoint URLs manually, fetch image metadata and use the provided CDN URLs. These include the version parameter and point directly to CDN edge locations for optimal performance.
Basic Responsive Images with srcset
The srcset attribute tells the browser which images are available, letting it choose the best one based on screen size and pixel density.
Pixel Density Descriptors (1x, 2x, 3x)
Use for fixed-size images where only screen pixel density varies:
<img
src="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small"
srcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 1x,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 2x,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large 3x
"
alt="1989 Upper Deck Ken Griffey Jr. #1"
loading="lazy"
/>
When to use: Fixed-width thumbnails in card lists or grids.
Width Descriptors (w)
Use when the image size changes based on viewport width:
<img
src="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small"
srcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 150w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 300w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large 600w,
https://api.tradingcardapi.com/v1/card-images/abc123/download 1200w
"
sizes="(max-width: 640px) 150px,
(max-width: 1024px) 300px,
600px"
alt="1989 Upper Deck Ken Griffey Jr. #1"
loading="lazy"
/>
When to use: Responsive layouts where image width changes with viewport.
The sizes Attribute
The sizes attribute tells the browser how wide the image will be displayed at different viewport widths.
Example: Card Grid Layout
<!--
Mobile (< 640px): Full width = 100vw
Tablet (640px - 1024px): 2 columns = 50vw each
Desktop (> 1024px): 4 columns = 25vw each
-->
<img
src="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small"
srcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 150w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 300w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large 600w
"
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
25vw"
alt="Card image"
loading="lazy"
/>
Example: Fixed-Width Sidebar
<!-- Sidebar is always 300px wide -->
<img
src="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small"
srcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 150w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 300w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large 600w
"
sizes="300px"
alt="Card image"
loading="lazy"
/>
The Picture Element
Use the <picture> element for art direction - when you want different images at different viewport sizes (not just scaled versions).
Example: Different Crops for Mobile
<picture>
<!-- Mobile: Show cropped front of card only -->
<source
media="(max-width: 640px)"
srcset="https://api.tradingcardapi.com/v1/card-images/front123/download?size=medium"
/>
<!-- Desktop: Show full card with both sides -->
<source
media="(min-width: 641px)"
srcset="
https://api.tradingcardapi.com/v1/card-images/front123/download?size=large,
https://api.tradingcardapi.com/v1/card-images/back123/download?size=large
"
/>
<!-- Fallback -->
<img
src="https://api.tradingcardapi.com/v1/card-images/front123/download?size=medium"
alt="1989 Upper Deck Ken Griffey Jr."
loading="lazy"
/>
</picture>
Lazy Loading
Lazy loading defers image loading until they're about to enter the viewport, drastically improving initial page load times.
Native Lazy Loading
Modern browsers support native lazy loading:
<img
src="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small"
srcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 150w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 300w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large 600w
"
sizes="(max-width: 640px) 150px, 300px"
alt="Card image"
loading="lazy"
/>
Browser support: All modern browsers (95%+ global support)
Intersection Observer (Advanced)
For more control, use the Intersection Observer API:
// Create observer
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
// Load the image
img.src = img.dataset.src;
if (img.dataset.srcset) {
img.srcset = img.dataset.srcset;
}
// Remove placeholder class
img.classList.remove('lazy-loading');
img.classList.add('lazy-loaded');
// Stop observing this image
observer.unobserve(img);
}
});
}, {
rootMargin: '50px' // Start loading 50px before entering viewport
});
// Observe all lazy images
document.querySelectorAll('img.lazy').forEach(img => {
imageObserver.observe(img);
});
HTML:
<img
class="lazy lazy-loading"
data-src="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium"
data-srcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 150w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 300w
"
alt="Card image"
/>
Framework Examples
React / Next.js
Next.js includes an optimized Image component:
import Image from 'next/image';
function CardImage({ imageId, alt }) {
const imageLoader = ({ src, width }) => {
// Map Next.js width to API size parameter
const sizeMap = {
150: 'small',
300: 'medium',
600: 'large'
};
const size = sizeMap[width] || 'small';
return `https://api.tradingcardapi.com/v1/card-images/${imageId}/download?size=${size}`;
};
return (
<Image
loader={imageLoader}
src={imageId}
alt={alt}
width={300}
height={400}
sizes="(max-width: 640px) 150px, 300px"
loading="lazy"
/>
);
}
Vue.js
<template>
<img
:src="getImageUrl(imageId, 'small')"
:srcset="generateSrcset(imageId)"
:sizes="sizes"
:alt="alt"
loading="lazy"
/>
</template>
<script>
export default {
props: {
imageId: String,
alt: String,
sizes: {
type: String,
default: '(max-width: 640px) 150px, 300px'
}
},
methods: {
getImageUrl(id, size) {
return `https://api.tradingcardapi.com/v1/card-images/${id}/download?size=${size}`;
},
generateSrcset(id) {
return `
${this.getImageUrl(id, 'small')} 150w,
${this.getImageUrl(id, 'medium')} 300w,
${this.getImageUrl(id, 'large')} 600w
`.trim();
}
}
};
</script>
Vanilla JavaScript
class CardImageRenderer {
constructor(imageId) {
this.imageId = imageId;
this.baseUrl = 'https://api.tradingcardapi.com/v1/card-images';
}
getImageUrl(size) {
const sizeParam = size ? `?size=${size}` : '';
return `${this.baseUrl}/${this.imageId}/download${sizeParam}`;
}
generateSrcset() {
return `
${this.getImageUrl('small')} 150w,
${this.getImageUrl('medium')} 300w,
${this.getImageUrl('large')} 600w,
${this.getImageUrl()} 1200w
`.trim();
}
render(alt, sizes = '(max-width: 640px) 150px, 300px') {
return `
<img
src="${this.getImageUrl('small')}"
srcset="${this.generateSrcset()}"
sizes="${sizes}"
alt="${alt}"
loading="lazy"
/>
`;
}
}
// Usage
const renderer = new CardImageRenderer('abc123');
document.getElementById('card-container').innerHTML = renderer.render(
'1989 Upper Deck Ken Griffey Jr. #1',
'(max-width: 640px) 100vw, 300px'
);
Performance Best Practices
1. Choose the Right Variant
| Use Case | Recommended Size | Reasoning |
|---|---|---|
| Mobile list thumbnails | small (150px) | Fast loading on cellular |
| Tablet/desktop lists | medium (300px) | Good balance for standard displays |
| Detail view (mobile) | large (600px) | Sharp on retina mobile screens |
| Detail view (desktop) | original | Full quality for zoom/inspection |
| Print/export | original | Maximum quality preserved |
2. Use Appropriate Formats
All Card Images API variants are JPEG format with quality optimization:
- Small: 75% quality - Optimized for thumbnails
- Medium: 80% quality - Balanced quality/size
- Large: 85% quality - High quality for larger displays
3. Implement Lazy Loading
Always use loading="lazy" for images below the fold:
<!-- Above the fold: eager loading -->
<img src="..." alt="..." loading="eager" />
<!-- Below the fold: lazy loading -->
<img src="..." alt="..." loading="lazy" />
4. Preload Critical Images
For hero images or featured cards, use <link rel="preload">:
<head>
<link
rel="preload"
as="image"
href="https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large"
imagesrcset="
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=small 150w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=medium 300w,
https://api.tradingcardapi.com/v1/card-images/abc123/download?size=large 600w
"
imagesizes="(max-width: 640px) 150px, 300px"
/>
</head>
5. Cache Images Locally
For frequently accessed images, implement client-side caching:
class ImageCache {
constructor() {
this.cache = new Map();
}
async get(imageId, size) {
const key = `${imageId}-${size}`;
if (this.cache.has(key)) {
return this.cache.get(key);
}
const url = `https://api.tradingcardapi.com/v1/card-images/${imageId}/download?size=${size}`;
const response = await fetch(url);
const blob = await response.blob();
const objectUrl = URL.createObjectURL(blob);
this.cache.set(key, objectUrl);
return objectUrl;
}
}
Mobile Considerations
Bandwidth Awareness
Use the Network Information API to adapt image quality based on connection:
function getOptimalSize() {
// Check if Network Information API is available
if ('connection' in navigator) {
const connection = navigator.connection;
// Slow connections: use small images
if (connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g') {
return 'small';
}
// Medium connections: use medium images
if (connection.effectiveType === '3g') {
return 'medium';
}
}
// Fast connections or unknown: use large images
return 'large';
}
// Usage
const optimalSize = getOptimalSize();
const imageUrl = `https://api.tradingcardapi.com/v1/card-images/abc123/download?size=${optimalSize}`;
Data Saver Mode
Respect user preferences for reduced data usage:
function shouldLoadHighQuality() {
if ('connection' in navigator && 'saveData' in navigator.connection) {
return !navigator.connection.saveData;
}
return true; // Default to high quality if unknown
}
const size = shouldLoadHighQuality() ? 'large' : 'small';
Troubleshooting
Thumbnails Not Available
Problem: Requesting a thumbnail returns the original image
Solutions:
- Wait a few seconds - thumbnails are generated asynchronously
- Poll the card-images endpoint to check if variants are ready
- Show a loading state while thumbnails generate
- Fall back to original if thumbnails aren't critical
Images Not Loading
Problem: Images fail to load or show broken image icon
Solutions:
- Verify image ID is correct
- Check authentication token is valid
- Ensure image hasn't been soft-deleted
- Check network console for error responses
Poor Performance
Problem: Images load slowly or consume too much bandwidth
Solutions:
- Always use
loading="lazy"for below-fold images - Use smaller variants for mobile devices
- Implement srcset for responsive delivery
- Enable CDN caching with appropriate headers
- Preload only critical above-fold images
srcset Not Working
Problem: Browser always loads the same image regardless of screen size
Solutions:
- Check that width descriptors match actual image widths
- Verify sizes attribute accurately reflects layout
- Test in different browsers (srcset support is universal in modern browsers)
- Clear browser cache and hard reload
Next Steps
- Working with Images Guide - Learn how to upload and manage card images
- Building a Card Tracker - See responsive images in action
- API Reference - Card Images - Complete endpoint documentation
- Code Examples - View implementation examples in your preferred language