# Build a Profile / Avatar Upload with Cropping

Source: https://www.techinterview.org/post/3233475389/build-profile-avatar-upload-with-cropping/
Updated: 2026-06-30 · techinterview.org

"Build an avatar upload" is a classic frontend machine-coding question that looks simple until you implement it. The hard parts: image rotation from EXIF, the cropping interaction, processing the cropped image at the right resolution, and the upload error handling. This guide covers what makes a good answer.

## Clarify scope

- Square crop only or any aspect ratio?

- Single avatar or multiple sizes (thumbnail, banner, etc.)?

- Drag-and-drop and click-to-select?

- Mobile camera capture in scope?

- Direct upload to S3 or via your server?

## The picker

- Hidden `<input type="file" accept="image/*">`

- Click trigger; or drag-drop zone with `onDragOver` / `onDrop`

- Multiple file types: PNG, JPG, WebP, HEIC (iOS), GIF (animated)

- Size limit and validation (e.g., 10 MB max)

- "Take a photo" on mobile via `capture="user"` attribute

## The EXIF rotation trap

iOS photos often have an EXIF orientation flag rather than rotated pixels. Naive rendering shows them sideways:

- Read EXIF data with a library (exifr, exif-parser)

- Apply rotation in canvas before display

- Modern browsers respect EXIF for `<img>` elements but not always for canvas; do not rely on it

## The HEIC challenge

- iOS photos are often HEIC, which Safari renders but Chrome / Firefox do not

- Convert to JPEG / WebP server-side or with heic2any in the browser

- Handle gracefully; do not show "broken image" if user uploads HEIC

## The crop interaction

The standard pattern:

- Image visible with a crop overlay (square or aspect-ratio constrained)

- Drag the crop box to reposition

- Pinch / wheel to zoom the underlying image

- Apply / Cancel buttons

Use a library (react-easy-crop, react-image-crop) or implement with canvas + pointer events. For interview, a small custom one demonstrates skill; for production, the libraries are battle-tested.

## Processing the crop

- Draw the original image to a hidden canvas

- Translate / scale based on crop selection

- Read back as a Blob using `canvas.toBlob`

- Specify output format (image/webp for size, image/jpeg for compatibility)

- Specify quality (0.8 is a reasonable default)

## Output sizing

- Most products use 256×256 or 512×512 for avatars

- Generate multiple sizes server-side for responsive display

- If client-side, use `OffscreenCanvas` for non-blocking processing

## Upload

### Direct-to-S3 (signed URL)

- Server generates a signed PUT URL

- Client uploads directly to S3 using the URL

- Server records the resulting object key

- No server bandwidth cost; faster for users

### Upload through server

- Client POSTs Blob to your API

- Server validates, processes, stores

- Higher control; higher bandwidth cost

- Required if you do server-side image transformation

## Progress and feedback

- Show upload progress percentage (XMLHttpRequest or fetch with upload progress)

- Optimistic UI: show preview immediately, replace with server URL on success

- Error handling: surface clear errors; allow retry

- Cancellation: AbortController if the user navigates away

## Accessibility

- File input is keyboard-accessible by default; do not break it

- Crop interaction needs keyboard alternatives — arrow keys to move, +/- to zoom

- Live region announces status: "Image selected, ready to crop", "Uploading 50%"

## Security and validation

- Validate MIME type client-side and server-side

- Reject obvious junk (text files renamed to .jpg)

- Server-side: re-encode the image to strip metadata and exploits

- Limit dimensions (10000×10000 → reject, prevents DoS)

## Privacy concerns

- EXIF data may include GPS coordinates of where the photo was taken

- Strip EXIF before storing user-uploaded images

- Document this in your privacy policy

## Mobile considerations

- iOS: `capture="user"` launches front camera; `capture="environment"` for back

- Pinch zoom in the cropper; touch-friendly drag

- Resize image before upload on mobile (data costs)

## Edge cases interviewers love

- User uploads a 50 MB photo — show error or auto-downscale before crop

- User uploads animated GIF — preserve animation in some products, freeze in others

- EXIF rotation — actually applies the rotation

- Network drops mid-upload — retry with backoff

- User navigates away mid-upload — abort, do not leave a half-uploaded blob

## What separates senior from staff

Senior implementations handle the upload + crop. Staff implementations address EXIF rotation, HEIC conversion, accessible crop interactions, and the multi-size server pipeline. Principal candidates discuss the security implications (re-encoding, EXIF stripping) and the on-demand image-resize pipeline (CDN with image transforms).

## Frequently Asked Questions

### Library options for production?

react-easy-crop, react-image-crop, Cropper.js (vanilla). For React Native, react-native-image-crop-picker. For full image-CDN handling, Cloudinary or imgix.

### Should I generate avatar sizes client-side?

Generally no — server-side image transforms (sharp, ImageMagick) are more reliable. Client-side is appropriate when you want to upload only the cropped result and avoid bandwidth.

### What about animated avatars?

GIFs and short videos are increasingly common. Decide product policy: allow or freeze to first frame. For mid-tier products, freezing is the norm.
