Skip to content
Bugwise
Menu
Features & Flows

Image Upload

How photo and file uploads work on iOS, Android and the web, why HEIC, EXIF rotation, big files and bad networks break them, and how to test uploads end to end.

35 min intermediate Mobile & web

A seller on a second-hand marketplace takes three photos of her sofa and taps Publish. The first photo shows up lying on its side. The second fails with “Something went wrong”. The third uploads fine, and with it, hidden inside the file, the GPS coordinates of her living room, which any buyer can now download.

Profile pictures, receipts in expense apps, ID checks in banking apps, damage photos in insurance claims, food photos in reviews: image upload is everywhere. It looks like one button, but behind it are cameras, permissions, a dozen file formats, huge files, flaky networks and real privacy risks. That’s why upload is a feature where testers who know what to feed it find a lot of serious bugs.

How it works

  1. The user picks a source. On a phone: take a new photo with the camera, or choose from the photo library (the system photo picker) or the Files app. On the web: a file chooser (<input type="file">), drag and drop, or paste from the clipboard. On phones, the browser’s file chooser also offers the camera and photo library.
  2. The app may need permission. Using the camera inside the app needs the user’s permission (on Android, an app that simply hands off to the system camera app may not). Photo library access depends on how the app asks (more below).
  3. The app checks the file. Is it an allowed type? Is it under the size limit? Are there too many files? Good apps check before uploading, so the user doesn’t wait a minute just to get an error.
  4. The app prepares the image. Often it resizes and compresses (a 12-megapixel photo is rarely needed for a 400-pixel avatar), converts formats, applies rotation and removes private metadata.
  5. The upload runs. The file is sent over HTTPS, ideally with a progress bar and a Cancel button. On a slow network this can take a long time, so the app must handle drops, retries and the user leaving the screen.
  6. The server validates it again. It checks the real content (not just the file name), the size, and the type, then usually re-encodes the image and creates thumbnails. Never trust the client: anyone can skip the app’s checks.
  7. The app shows the result. A thumbnail, a clear error, or a “Retry” option. The uploaded image should look exactly like the one the user picked.

Sources and permissions

SourceiOSAndroidWeb
CameraPermission prompt on first usePermission prompt on first use capture on a file input opens the phone’s camera app; a live camera view inside the page makes the browser ask for permission
Photo pickerSystem picker: no permission. Full library access: prompt with Limit AccessPhoto Picker: no permission. Media access: Android 14+ allows selected photos onlyFile input opens the phone picker or desktop dialog
Files / drag & drop / pasteFiles app via document pickerFiles via the system file chooserDrag onto a drop zone, or paste a screenshot with Ctrl/Cmd+V

PermissionsApp permissionsThe user's approval for an app to use things like the camera, location, contacts or notifications.Open in glossary → create their own test cases. The system shows a modal the app can’t style, and the user can say Don’t Allow, pick Limit Access / selected photos only, or later revoke access in Settings. Each answer needs a sensible result: no crash, no empty screen, and a clear way to the Settings app if the user changes their mind. The differences between platforms are covered in iOS vs Android.

Formats, sizes and the files you should keep ready

FormatWhere it comes fromWhat to watch
JPEGMost cameras, Android, older iPhonesBig files from modern cameras, EXIF rotation
HEICiPhone camera default (“High Efficiency”)Servers and browsers that don’t support it; must be accepted or converted
PNGScreenshots, logos, graphicsTransparency turned black or white; large file sizes
WebPWeb downloads, some Android appsAccepted by the server? Shown correctly everywhere?
GIFMemes, animationsAnimation lost after resizing, or rejected without a clear message

Every product has limits: allowed types, a maximum file size (for example 10 MB), maybe a maximum resolution and a maximum number of files. Treat them like any other rule and use boundary value analysisBoundary value analysisTesting values at and just around the edges of valid ranges, where bugs love to hide.Open in glossary →: just under, exactly at, and just over the limit. And the user must be told the limit, ideally before they pick, and again in the error.

EXIF: rotation and location hidden in the file

Phone cameras don’t actually rotate the image when you hold the phone upright. They save the pixels as the sensor saw them, and add a small EXIF tag (photo metadata) called Orientation that says “rotate this 90° when you show it”. Apps that ignore that tag show portrait photos sideways. EXIF can also contain the camera model, the date and the exact GPS location where the photo was taken.

Try it: pick the portrait photo, then switch the app’s handling on and off. Then see what the server keeps.

Photo taken

1. Pixels stored in the file

Pixel size4032 × 3024
Orientation6 (rotate 90° clockwise)
CameraiPhone 15
GPS45.8150 N, 15.9819 E

2. What the app shows

The app ignored the tag and drew the raw pixels. This is the classic "my photo uploaded sideways" bug.

3. What the server keeps

Pixel size4032 × 3024
Orientation6 (rotate 90° clockwise)
CameraiPhone 15
GPS45.8150 N, 15.9819 E

Anyone who downloads this photo can see where it was taken, often the seller's home.

Upload on a real network

A 4 MB photo takes a fraction of a second on office Wi-Fi and half a minute on a weak mobile signal. Testers check what happens in between:

  • Progress: the bar moves, and after reaching 100% the app shows that the server is still processing (instead of a full bar that seems frozen).
  • Cancel: the user can stop an upload that’s taking too long or was the wrong photo.
  • Lost connection: the app tells the user, keeps the photo, and retries when the network returns (or offers a Retry button). It never silently drops the photo. See Network conditions for how to simulate this.
  • Leaving the app: if the user switches apps or locks the phone, either the upload continues in the background (iOS and Android both support background transfers) or it resumes cleanly when the app returns (Background and foreground).
  • Double submit: tapping Post twice must not upload the same photo twice.

Server-side validation (the defensive basics)

File upload is one of the classic places where attackers try to sneak in something that isn’t an image. You don’t need to be a security expert to check the basics in a test environment with harmless test files:

  • Rename a text file (or a PDF) to photo.jpg and upload it. The server should reject it because it looks at the content, not the name. A clear message like “This file isn’t a valid image” is enough.
  • Upload a file over the size limit through the web version and through the app. Both should be rejected by the server too, not only by the app.
  • After a successful upload, open the stored image’s URL. It should be served as an image, from a random-looking file name, and the original file name shouldn’t be used in the path.
  • Check the stored file’s metadata: no location data where the spec says it must be removed.

Report anything suspicious and let the security team go deeper. See Security basics for the wider picture.

Example requirements

What usually goes wrong

#BugWhat you seeTypical severity
1HEIC not supportediPhone photos fail, often with a generic errorHigh (many users affected)
2EXIF orientation ignoredPortrait photos sideways or upside down, in the app, on the web or only in thumbnailsMedium–High
3Size limit hiddenBig files upload for a minute and then fail, with no limit mentionedMedium
4No progress, no cancelSpinner forever, bar stuck at 100%, no way to stopMedium
5Network loss handled badlyPhoto silently disappears, or the app hangs; no retryHigh
6Location metadata keptDownloaded photo reveals where the user livesHigh (privacy)
7Transparency lostTransparent PNG logo gets a black backgroundLow–Medium
8Over-compressionUploaded photo is blurry or blocky, text in receipts unreadableMedium
9Permission edge casesCrash or blank screen after “Don’t Allow” or limited accessHigh
10Content not validated on the serverA renamed non-image file is accepted and storedHigh (security)
11DuplicatesDouble tap or retry uploads the same photo twiceLow–Medium
12Accessibility gapsUpload button with no label, progress not announced, drag and drop onlyMedium–High

Find the bug

Swapsy’s “New listing” screen below has six bugs. Use the test photo library like a tester would:

  • Add photos one at a time and several at once. Read every message.
  • Compare each thumbnail with the photo in the picker.
  • Switch the network to Slow 3G, watch the progress bar, then try Offline in the middle of an upload.
  • Tap uploaded photos to see what the server stored, and watch the network log.
  • Check the Files tab too.

🐞 Bug hunt: Swapsy photo upload

This demo has 6 hidden bugs. Explore it like a tester, then check your findings.

Found0/6
9:41
CancelNew listingNext

Photos · 0/5

Add up to 5 photos. The first one is the cover.

Details

TitleTeal 3-seat sofa
Price€180

Network

From the spec

Accepted: JPEG, PNG, HEIC, WebP · max 10 MB per photo · up to 5 photos. Uploads can be canceled. Location data must be removed before photos are stored.

Tap an uploaded photo to see what the server stored. Use Slow 3G to watch uploads closely.

Network log

  • Add photos to see requests…
  1. 1

    Hint: Add IMG_2041.HEIC, the iPhone camera default format.

  2. 2

    Hint: Add IMG_2087.JPG and compare the thumbnail with the picker.

  3. 3

    Hint: Add DSC_0912.JPG (12.4 MB) and read the error.

  4. 4

    Hint: Switch to Slow 3G and add a photo. Try to stop it.

  5. 5

    Hint: Start an upload on Slow 3G, then switch to Offline.

  6. 6

    Hint: Tap an uploaded phone photo and read what the server stored.

Test scenarios

Functional

  • Add a photo from the camera, the photo library and Files. On the web: file chooser, drag and drop, paste.
  • Add one photo, then several at once, then exactly the maximum, then try one more.
  • Each accepted format uploads and looks right: JPEG, PNG, HEIC, WebP (and GIF if supported).
  • Remove a photo, reorder photos (if supported), replace the cover photo.
  • The uploaded image looks the same in the app, on the web, and in notifications or emails that show it.

Negative

  • A file over the size limit, a format that isn’t allowed, a 0-byte file, a corrupted image.
  • A non-image file renamed to .jpg (use a harmless text file).
  • Don’t Allow for camera or photos; then enable it later in Settings and come back.
  • Cancel the picker without choosing anything: the app should return to where it was.

Edge cases

  • Boundaries: a file just under, exactly at and just over the size limit; the maximum number of photos and one more.
  • Rotation: portrait, landscape, upside down and selfie (front camera) photos. Check thumbnails, full view and the web version.
  • Extreme shapes: a very wide panorama, a 1×1 pixel image, a huge-resolution image under the size limit.
  • Transparency: a transparent PNG keeps its transparency (or gets an intentional background).
  • Limited photo access on iOS and Android 14+: only selected photos are visible, and the user can add more.
  • Same photo twice, and double tapping Upload or Post.

Network and app lifecycle

Security and privacy

Accessibility

Example test cases

TC-UPL-001Upload a HEIC photo from an iPhone

Preconditions

  • iPhone camera format set to High Efficiency
  • A new photo taken with the camera

Steps

  1. Open New listing
  2. Tap Add photos and choose the photo
  3. Wait for the upload to finish
  4. Open the listing on the website

Expected result

The photo uploads without errors and is shown correctly in the app and on the website (stored as JPEG).

TC-UPL-002Portrait photo is shown upright

Preconditions

  • Photo taken holding the phone upright (EXIF orientation 6)

Steps

  1. Add the photo to a listing
  2. Check the thumbnail, the full-screen view and the website

Expected result

The photo is upright everywhere. Stored dimensions are portrait (e.g. 3024 × 4032).

TC-UPL-003Size limit boundaries

Steps

  1. Add a 9.9 MB photo
  2. Add a photo of exactly 10 MB
  3. Add a 10.1 MB photo

Test data

Limit: 10 MB per photo

Expected result

9.9 MB and 10 MB upload. 10.1 MB is rejected before uploading with "This photo is larger than 10 MB. Choose a smaller one."

TC-UPL-004Location metadata is removed

Preconditions

  • A JPEG photo that contains GPS coordinates

Steps

  1. Upload the photo
  2. Download the stored image from the listing
  3. Inspect it with an EXIF viewer

Expected result

No GPS or camera metadata in the stored image. The photo is still upright.

TC-UPL-005Connection lost during upload

Preconditions

  • Network throttled to a slow 3G profile

Steps

  1. Add a 4 MB photo
  2. At about 50%, switch on airplane mode
  3. Wait 10 seconds
  4. Switch airplane mode off

Expected result

The photo stays in the grid with "Waiting for connection" and finishes uploading after the network returns. Only one copy is stored.

TC-UPL-006Cancel an upload

Preconditions

  • Slow network

Steps

  1. Add a large photo
  2. Tap the cancel (×) button while it uploads

Expected result

The upload stops, the photo is removed from the grid, and the server does not store it.

TC-UPL-007Renamed non-image file is rejected

Preconditions

  • Test environment
  • A plain text file renamed to notes.jpg

Steps

  1. Upload notes.jpg from Files (app) or the file chooser (web)

Expected result

The upload is rejected by the server with a specific message ("This file isn't a valid image"). Nothing is stored.

TC-UPL-008Photo access denied

Preconditions

  • Fresh install

Steps

  1. Tap Add photos › Take photo
  2. Choose "Don't Allow" for camera access
  3. Tap Take photo again

Expected result

No crash. The app explains why it needs the camera and offers a button that opens the app's Settings page.

Tip: click a test case to expand it.

Mobile vs web

  • Photo pickers: the iOS system picker and the Android Photo Picker don’t need library permission. Apps that build their own gallery do, and must handle full, limited and denied access. On Android, test both new and older OS versions, because the permission model changed several times (iOS vs Android).
  • HEIC: iPhones save HEIC by default. Some apps let the system convert to JPEG when picking; others send HEIC as-is. Test with a real iPhone photo, not a downloaded JPEG.
  • Camera: test the front and back cameras, flash, and rotating the phone while the camera is open.
  • Getting test photos onto devices: drag images onto the iOS Simulator, or adb push photo.jpg /sdcard/Pictures/ on Android (the gallery may need a moment, or a reboot of the emulator, to show it).
  • Background uploads: lock the phone or switch apps mid-upload. Does it finish, resume or fail clearly?
  • Storage and memory: picking ten 48-megapixel photos at once can crash apps that load full-size images into memory. Try it on an older, low-memory device.
  • Network: use the Network Link Conditioner (iOS) or emulator network settings (Android), and airplane mode on real devices (Network conditions).
  • File chooser: check the accept filter (does the dialog hide non-images?), multiple selection, and that the “All files” option still gets validated.
  • Drag and drop: drop one file, several files, a folder, a non-image, and a file onto the page outside the drop zone (the browser shouldn’t just open the image and leave your page).
  • Paste: paste a screenshot from the clipboard with Ctrl/Cmd+V, if the feature supports it.
  • Mobile browsers: on phones the file input offers camera, photo library and files. iOS Safari may convert HEIC to JPEG on the way (depending on the input’s accept list); don’t assume, check what the server received.
  • DevTools: throttle the network, watch the upload request, its size and status code (DevTools for testers). Try going offline from the Network panel mid-upload.
  • Leaving the page: refreshing or closing the tab during an upload should warn the user or resume cleanly.
  • Cross-browser: check Chrome, Safari and Firefox, especially for HEIC, WebP and EXIF rotation.

Checklist

Image upload checklist

0 of 14 checked

Check your understanding

Quick quiz

0/6 answered · 0 correct

  1. 1.An iPhone user's portrait photo shows up sideways after upload, but landscape photos are fine. What is the most likely cause?

  2. 2.Uploads from iPhones fail, uploads from Android phones work. Which format should you test first?

  3. 3.The limit is 10 MB. Which set of files gives the best boundary test?

  4. 4.Why is location data in an uploaded photo a problem on a marketplace?

  5. 5.You rename notes.txt to notes.jpg and the server accepts it. What does this tell you?

  6. 6.A photo is uploading on a weak signal and the user loses connection. What is the best behavior?

Key takeaways

  • Upload is a flow: source, permission, client checks, preparation (resize, rotate, strip metadata), upload, server validation, result. Bugs hide in every step.
  • Keep a test kit: HEIC, portrait, huge, just-under-the-limit, transparent PNG, GIF, WebP, a photo with GPS, a 0-byte file and a renamed non-image.
  • The classic bugs: HEIC rejected, sideways photos, hidden size limits, no cancel or progress, silent loss when offline, and location data left in the file.
  • Test uploads on slow and lost networks and while the app goes to the background.
  • Never trust the client: the server must check the real content, the size and the type, and errors must say exactly what’s wrong.

Finished this page?Nice work, this page is complete!

Mark it as done to track your progress. It's saved in this browser, no account needed.

Its review cards are now in Bites ⚡
Esc

Type to search the whole site.