Working with Images
Mushu provides on-demand image transforms via URL. Only the original is stored; variants are generated and cached at the edge on first request.
Named Variants
Every uploaded image is available in these predefined variants:
| Variant | Size | Use Case |
|---|---|---|
original | Original size | Full resolution downloads |
thumbnail | 150x150 (cover) | Grid views, lists |
small | 320px width | Mobile previews |
medium | 640px width | Standard display |
large | 1280px width | Hero images, galleries |
Custom Sizes
For sizes not covered by named variants, use the custom endpoint
with URL parameters:
https://images.mushucorp.com/t/custom/KEY?w=WIDTH&h=HEIGHT&fit=FIT&gravity=GRAVITY&q=QUALITY Parameters
| Param | Values | Default | Description |
|---|---|---|---|
w | 1-2000 | required | Width in pixels |
h | 1-2000 | optional | Height in pixels (maintains aspect ratio if omitted) |
fit | cover, contain, scale-down, crop | cover | How to fit image to dimensions |
gravity | auto, face, center | auto | Focus point when cropping |
q | 1-100 | 85 | Output quality |
Avatar Example
For profile photos with face detection:
<!-- 128x128 avatar with face detection -->
<img
src="https://images.mushucorp.com/t/custom/org_xxx/photo.jpg?w=128&h=128&gravity=face"
width="128"
height="128"
alt="Profile"
/>
<!-- Common avatar sizes -->
<img src=".../t/custom/KEY?w=32&h=32&gravity=face" /> <!-- tiny -->
<img src=".../t/custom/KEY?w=64&h=64&gravity=face" /> <!-- small -->
<img src=".../t/custom/KEY?w=128&h=128&gravity=face" /> <!-- medium -->
<img src=".../t/custom/KEY?w=200&h=200&gravity=face" /> <!-- standard -->
<img src=".../t/custom/KEY?w=400&h=400&gravity=face" /> <!-- high-DPI --> Width-Only Resize
Omit h to maintain aspect ratio:
<!-- Resize to 500px wide, height calculated automatically -->
<img src="https://images.mushucorp.com/t/custom/org_xxx/photo.jpg?w=500" /> Getting Image URLs
CLI
mushu media url MEDIA_ID --variant thumbnail API
GET /media/{media_id}/images
Authorization: Bearer YOUR_TOKEN Response:
{
"media_id": "media_abc123",
"original": "https://images.mushucorp.com/t/original/org_xxx/media_abc123/photo.jpg",
"thumbnail": "https://images.mushucorp.com/t/thumbnail/org_xxx/media_abc123/photo.jpg",
"small": "https://images.mushucorp.com/t/small/org_xxx/media_abc123/photo.jpg",
"medium": "https://images.mushucorp.com/t/medium/org_xxx/media_abc123/photo.jpg",
"large": "https://images.mushucorp.com/t/large/org_xxx/media_abc123/photo.jpg"
} URL Format
Image URLs follow this pattern:
https://images.mushucorp.com/t/VARIANT/KEY Where:
VARIANT- One of: original, thumbnail, small, medium, large, or custom (with params)KEY- The storage key from the media item
Using in HTML
<!-- Responsive image with srcset -->
<img
src="https://images.mushucorp.com/t/medium/org_xxx/photo.jpg"
srcset="
https://images.mushucorp.com/t/small/org_xxx/photo.jpg 320w,
https://images.mushucorp.com/t/medium/org_xxx/photo.jpg 640w,
https://images.mushucorp.com/t/large/org_xxx/photo.jpg 1280w
"
sizes="(max-width: 320px) 320px, (max-width: 640px) 640px, 1280px"
alt="My photo"
/>
<!-- Thumbnail for lists -->
<img
src="https://images.mushucorp.com/t/thumbnail/org_xxx/photo.jpg"
width="100"
height="100"
alt="Thumbnail"
/> Using in iOS
import SDWebImage
// Load thumbnail in a collection view cell
imageView.sd_setImage(with: URL(string: media.thumbnailUrl))
// Load full size with placeholder
imageView.sd_setImage(
with: URL(string: media.largeUrl),
placeholderImage: UIImage(named: "placeholder")
) Using in React
function MediaImage({ media, variant = 'medium' }) {
const baseUrl = 'https://images.mushucorp.com/t';
return (
<picture>
<source
media="(min-width: 1024px)"
srcSet={`${baseUrl}/large/${media.key}`}
/>
<source
media="(min-width: 640px)"
srcSet={`${baseUrl}/medium/${media.key}`}
/>
<img
src={`${baseUrl}/${variant}/${media.key}`}
alt={media.filename}
loading="lazy"
/>
</picture>
);
} Image Processing Details
- Format - Output is WebP for better compression (JPEG fallback)
- Quality - 85% quality for optimal size/quality balance
- Caching - Images are cached at Cloudflare's edge globally
- On-Demand - Variants are generated on first request, then cached
Listing Images
CLI
mushu media list --org ORG_ID --type image API
GET /media/org/{org_id}?media_type=image
Authorization: Bearer YOUR_TOKEN Deleting Images
CLI
mushu media delete MEDIA_ID API
DELETE /media/{media_id}
Authorization: Bearer YOUR_TOKEN Deletion removes the original file from R2. Cached variants will expire based on CDN TTL settings (typically within 24 hours).
FAQ
Can I request custom sizes?
Yes! Use the /t/custom/KEY endpoint with URL parameters.
See Custom Sizes above.
What happens if I request a variant for a video?
The image endpoints only work for media with media_type: "image".
For video thumbnails, use the video endpoint.
Are there rate limits?
Image transforms are rate-limited to prevent abuse. Normal usage (thousands of requests per day) won't hit limits.
Can I hotlink images?
Yes, image URLs are public and can be used anywhere. Consider the security implications for sensitive content.