Works with any backend npm install Zero dependencies

Launch the device camera directly on mobile - skip the gallery

cameraCapture sets the HTML5 capture attribute on the file input. On mobile, tapping the upload button launches the camera directly instead of the gallery / file picker - perfect for receipt-scanning, ID-upload, profile-photo, or any "capture-then-upload" workflow. On desktop, it's a no-op (the input still opens the standard file picker).

Best tested on a phone - desktop browsers ignore the attribute
Try it: open this page on a phone (or use Chrome DevTools' device emulation). Pick a mode, tap the "Take photo" button:
  • "environment" -> rear camera opens directly (good for documents, scans, photos of things)
  • "user" -> front camera opens directly (good for selfies, profile photos)
  • "Off" -> standard gallery picker with optional camera option
Configuration
new MultipleUpload('#uploader', {
 uploadUrl: '/api/upload',
 accept: 'image/*', // optional: restrict to images
 cameraCapture: 'environment', // 'user' | 'environment' | true | false
 multiple: true
});
All four mode values
ValueEffect on mobileHTML attribute
'environment'Rear camera (document scan, photos of things)capture="environment"
'user'Front camera (selfies, profile pics, video calls)capture="user"
trueCamera (browser default - usually rear)capture="environment"
false / nullStandard gallery picker (default)(no attribute)
Pair with accept for video capture

The capture attribute respects accept - combine to drive video recording directly:

// Direct video recording from the rear camera:
new MultipleUpload('#uploader', {
 uploadUrl: '/api/upload',
 accept: 'video/*',
 cameraCapture: 'environment'
});

// Direct audio recording:
new MultipleUpload('#uploader', {
 uploadUrl: '/api/upload',
 accept: 'audio/*',
 cameraCapture: true // some browsers map to microphone
});
Recipes
Receipt scanning workflow
new MultipleUpload('#uploader', {
 uploadUrl: '/api/receipts',
 accept: 'image/*',
 cameraCapture: 'environment', // rear camera
 imagePreset: 'document', // auto-orient + compress, preserve resolution for OCR
 multiple: true,
 onTaskComplete: (task, result) => {
 runOcr(result.fileGuid); // your server's OCR pipeline
 }
});
Profile photo workflow
new MultipleUpload('#uploader', {
 uploadUrl: '/api/profile-photo',
 accept: 'image/*',
 cameraCapture: 'user', // front camera for selfies
 imagePreset: 'avatar', // 512x512 JPEG
 multiple: false,
 onTaskComplete: (task, result) => {
 updateUserAvatar(result.fileGuid);
 }
});
ID document upload (multi-step)
// Force rear camera + force image-only + enforce min image dimensions
new MultipleUpload('#uploader', {
 uploadUrl: '/api/id-verification',
 accept: 'image/*',
 cameraCapture: 'environment',
 minImageWidth: 800, // typical ID is 1000+px wide; reject tiny captures
 minImageHeight: 500,
 encrypt: true, // ID docs warrant encryption-at-rest
 encryptPassword: getUserSessionKey()
});
Browser support
  • Mobile Safari (iOS): camera launches directly; environment + user both honored.
  • Chrome Android: camera launches directly; same as iOS.
  • Samsung Internet: same as Chrome.
  • Desktop browsers: attribute is ignored - standard file picker opens. No fallback wiring needed.
  • Tablets: some treat themselves as desktop (iPad => Safari macOS UA); behavior is browser-dependent.
Why a dedicated option (vs documenting the raw HTML attribute)
  • Discoverability: shows up in autocomplete / docs / TypeScript intellisense alongside accept / multiple - easier to find than the underlying HTML attribute.
  • Validation: filters bad values; passing 'foo' just no-ops instead of producing an invalid attribute.
  • Symmetric with the rest of the API: all other input-related options are top-level (accept, multiple, webkitdirectory).