Cloudinary Integration Guide
This document explains the Cloudinary integration implemented for optimal image performance in your Expo Web application.
Overview
Cloudinary is integrated as the primary image optimization service, providing:
- Auto WebP/AVIF conversion - Automatic format optimization for browsers
- Smart CDN caching - Fast global response times via multi-CDN edge networks
- DPR-aware delivery - Device pixel ratio optimization
- Automatic resizing & smart cropping - On-the-fly transformations
- Zero infrastructure management - Upload → serve → done
- Browser-compatible - Works in Expo Web without Node.js dependencies
Configuration
Environment Variables
Your .env file already contains the Cloudinary configuration:
CLOUDINARY_URL=cloudinary://922669241128932:ZQiHZwQzJrScX63zjIW63iKs8R0@dfwjkpsma
This URL contains:
- Cloud Name:
dfwjkpsma - API Key:
922669241128932 - API Secret:
ZQiHZwQzJrScX63zjIW63iKs8R0
Browser-Compatible Implementation
The integration uses a custom URL builder that works in browser environments without requiring Node.js dependencies. This ensures compatibility with Expo Web while maintaining all Cloudinary optimization features.
Cloudinary Dashboard Setup
-
Create Upload Presets
- Go to Cloudinary Dashboard → Settings → Upload
- Create unsigned upload preset:
speaker_avatars - Settings:
- Folder:
speakers/avatars - Allowed formats:
jpg, jpeg, png, webp, avif - Transformation:
limit_1000x1000 - Quality:
auto:good - Format:
auto
- Folder:
-
Folder Structure
speakers/├── avatars/│ ├── john-doe.jpg│ ├── jane-smith.jpg│ └── ...└── banners/├── event-banner.jpg└── ...
Implementation
Core Components
1. Cloudinary Utility (lib/cloudinary.ts)
Provides optimized URL generation and upload functionality:
import { getAvatarUrl, getBannerUrl, uploadImage } from './lib/cloudinary';
// Optimized avatar URL
const avatarUrl = getAvatarUrl('speakers/avatars/john-doe', 100);
// Optimized banner URL
const bannerUrl = getBannerUrl('speakers/banners/event', 1200, 400);
// Upload image
const result = await uploadImage(file, {
folder: 'speakers/avatars',
tags: ['avatar', 'speaker']
});
2. Optimized Avatar Component (components/SpeakerAvatar.tsx)
Automatically uses Cloudinary URLs with fallback to local/S3:
<SpeakerAvatar
name="John Doe"
size={100}
showBorder={true}
/>
Priority Order:
- Cloudinary (optimized with WebP/AVIF, DPR, quality)
- Local optimized (
/assets/speakers/avatars/) - S3 bucket (fallback)
3. Image Upload Component (components/CloudinaryImageUpload.tsx)
Cross-platform image upload with validation:
<CloudinaryImageUpload
onUploadSuccess={(result) => console.log('Uploaded:', result)}
onUploadError={(error) => console.error('Upload failed:', error)}
placeholder="Upload Avatar"
/>
4. General Optimized Image (components/OptimizedImage.tsx)
For all image types with automatic optimization:
<OptimizedImage
source={{ uri: 'https://cloudinary.com/...' }}
width={300}
height={200}
quality="auto:good"
format="auto"
dpr="auto"
/>
URL Generation Examples
Avatar URLs
// Input: "John Doe", size: 100
// Output: https://res.cloudinary.com/dfwjkpsma/image/upload/c_fill,g_face,h_100,w_100,q_auto:best,f_auto,dpr_auto/speakers/avatars/john-doe
Banner URLs
// Input: "event-banner", width: 1200, height: 400
// Output: https://res.cloudinary.com/dfwjkpsma/image/upload/c_fill,g_auto,h_400,w_1200,q_auto:good,f_auto,dpr_auto/speakers/banners/event-banner
Thumbnail URLs
// Input: "image-id", width: 300, height: 200
// Output: https://res.cloudinary.com/dfwjkpsma/image/upload/c_fill,g_auto,h_200,w_300,q_auto:good,f_auto,dpr_auto/image-id
Performance Benefits
1. Format Optimization
- WebP: Chrome, Firefox, Edge (25-35% smaller than JPEG)
- AVIF: Chrome, Firefox (50% smaller than JPEG)
- Fallback: JPEG/PNG for unsupported browsers
2. Quality Optimization
q_auto: Automatically adjusts quality for optimal file sizeq_auto:best: Higher quality for avatarsq_auto:good: Balanced quality for banners
3. DPR Optimization
dpr_auto: Serves appropriate resolution for device- 1x: Standard displays
- 2x/3x: Retina/high-DPI displays
4. Smart Cropping
g_auto: AI-powered content-aware croppingg_face: Face detection for avatarsg_center: Center-focused cropping
Usage Guidelines
For Avatars
// Use SpeakerAvatar component for speaker images
<SpeakerAvatar name="Speaker Name" size={80} />
// Or use OptimizedAvatar for custom avatars
<OptimizedAvatar
source={{ uri: 'cloudinary-url' }}
size={100}
/>
For Banners/Hero Images
<OptimizedBanner
source={{ uri: 'cloudinary-url' }}
width={1200}
height={400}
/>
For General Images
<OptimizedImage
source={{ uri: 'image-url' }}
width={width}
height={height}
quality="auto:good"
/>
Upload Workflow
1. Client Upload (Recommended)
import CloudinaryImageUpload from './components/CloudinaryImageUpload';
// In your component
<CloudinaryImageUpload
onUploadSuccess={(result) => {
// result.public_id - Cloudinary public ID
// result.secure_url - Optimized URL
// Save to database
}}
/>
2. Server Upload (Advanced)
import { cloudinary } from './lib/cloudinary';
const result = await cloudinary.uploader.upload(file, {
folder: 'speakers/avatars',
public_id: 'custom-name',
transformation: [
{ width: 1000, height: 1000, crop: 'limit' },
{ quality: 'auto:good', format: 'auto' }
]
});
Migration Guide
Existing Local Images
- Upload existing avatar images to Cloudinary
- Use naming convention:
speakers/avatars/{speaker-name} - Update database with Cloudinary URLs (optional - will auto-generate)
Existing S3 Images
- Cloudinary integration works alongside S3
- Gradually migrate high-traffic images to Cloudinary
- Fallback ensures no broken images during migration
Monitoring & Analytics
Cloudinary provides detailed analytics:
- Bandwidth usage
- Transformation counts
- Popular images
- Geographic distribution
Access via: Cloudinary Dashboard → Analytics
Best Practices
- Use descriptive public IDs:
speakers/avatars/john-doevsabc123 - Organize in folders: Group related images
- Add tags: For easier management and analytics
- Set appropriate quality:
q_auto:bestfor avatars,q_auto:goodfor banners - Enable format auto:
f_autofor automatic WebP/AVIF - Use DPR auto:
dpr_autofor device-appropriate resolution
Troubleshooting
Common Issues
-
Upload fails
- Check upload preset configuration
- Verify API credentials
- Ensure file size < 10MB
-
Images not loading
- Check public ID format
- Verify folder structure
- Check transformations syntax
-
Performance issues
- Ensure
f_autoandq_autoare used - Check CDN caching headers
- Monitor transformation counts
- Ensure
Debug URLs
// Add debug parameters to URLs
const debugUrl = getCloudinaryUrl(publicId, {
width: 100,
height: 100,
// Add this for debugging
// Will show transformation details
});
// Check generated URLs
console.log('Cloudinary URL:', debugUrl);
Support
- Cloudinary Documentation: https://cloudinary.com/documentation
- React SDK: https://cloudinary.com/documentation/react_integration
- API Reference: https://cloudinary.com/documentation/image_upload_api_reference