Is it possible to control the camera's flashlight on a phone via a website? Say through Chrome or Firefox. I know it's possible using an Android or iOS app, which is implemented by all the flashlight apps out there. And I know one can control the cameras via the getUserMedia
family of functions. If not, does anyone know when will it become available?

- 393
- 1
- 4
- 15

- 4,010
- 6
- 21
- 34
-
Did you ever figure out whether you can do this, and if so how? – Eric Gurney Jan 18 '17 at 14:07
5 Answers
Here is a little "torch-app" for a website:
Edit 1: I also made a jsfiddle
//Test browser support
const SUPPORTS_MEDIA_DEVICES = 'mediaDevices' in navigator;
if (SUPPORTS_MEDIA_DEVICES) {
//Get the environment camera (usually the second one)
navigator.mediaDevices.enumerateDevices().then(devices => {
const cameras = devices.filter((device) => device.kind === 'videoinput');
if (cameras.length === 0) {
throw 'No camera found on this device.';
}
const camera = cameras[cameras.length - 1];
// Create stream and get video track
navigator.mediaDevices.getUserMedia({
video: {
deviceId: camera.deviceId,
facingMode: ['user', 'environment'],
height: {ideal: 1080},
width: {ideal: 1920}
}
}).then(stream => {
const track = stream.getVideoTracks()[0];
//Create image capture object and get camera capabilities
const imageCapture = new ImageCapture(track)
const photoCapabilities = imageCapture.getPhotoCapabilities().then(() => {
//todo: check if camera has a torch
//let there be light!
const btn = document.querySelector('.switch');
btn.addEventListener('click', function(){
track.applyConstraints({
advanced: [{torch: true}]
});
});
});
});
});
//The light will be on as long the track exists
}
<button class="switch">On / Off</button>
The code is heavily inspired by this repository, this webseries and this blog-post
Edit 2: This does only works in Chrome (and maybe Opera). It does not work in Chrome on iOS, because Chrome cannot access the camera. I cannot test it on android for now. I created a new jsfiddle, with an output. If you have an android phone and it does not work for you, it will maybe tell why: https://jsfiddle.net/jpa1vwed/
Feel free to debug, comment and edit.

- 1,780
- 1
- 18
- 19
-
5Does this work on iOS? I have a working app accessing the camera with getUserMedia in Safari 11 on iOS but the snipped is not working for me. Has anyone tested this? – martin Apr 03 '18 at 15:39
-
It can only work in Chrome, because `ImageCapture` is only supported in Chrome and Opera (I do not have Opera installed, so I cannot test it) for now. It does not work in chrome on Iphone anymore, I am currently looking into it. – Daniel Budick Feb 25 '19 at 10:36
-
Chrome cannot access the camera on iphone (https://stackoverflow.com/questions/51501642/chrome-and-firefox-are-not-able-to-access-iphone-camera), so this won't work either... I will test it in chrome on android, I need to find an android phone first. – Daniel Budick Feb 25 '19 at 10:42
-
I tried it on my old Galaxy S5, it does not find a camera with torch. Currently I don't have more time to spend on that problem, I hope someone else will find a solution. – Daniel Budick Feb 25 '19 at 11:05
-
3Could someone update this to add toggle functionality to the torch? As is once the torch is turned on, there's no turning it off – Stuart Oct 26 '19 at 00:16
-
2@DanielBudick Chrome can and does access both cameras on iPhone, you need to use the correct html5 input tag `` "environment" for rear facing and "user" for front facing. – devnullpointer May 28 '20 at 14:21
-
FYI, your code has many redundant lines and this even doesn't provide a way to detect torch or turn it off. You can check my answer for better version. – Bikram Kumar Apr 05 '22 at 13:59
-
how did you import the ImageCapture()? Its getting redline in mine... I'm running on angular 13 – frustrated-dev Mar 27 '23 at 15:30
You can use the MediaStream Image Capture API by creating an ImageCapture from a VideoStreamTrack and setting the option "fillLightMode" to "flash" or "torch". Example:
<video autoplay="true"></video>
<img />
<button onclick="takePhoto()">Take Photo</button>
<script type="text/javascript">
var imageCapture = null;
var deviceConfig = {
video: {
width: 480,
height: 640,
facingMode: "environment", /* may not work, see https://bugs.chromium.org/p/chromium/issues/detail?id=290161 */
deviceId: null
}
};
var imageCaptureConfig = {
fillLightMode: "torch", /* or "flash" */
focusMode: "continuous"
};
// get the available video input devices and choose the one that represents the backside camera
navigator.mediaDevices.enumerateDevices()
/* replacement for not working "facingMode: 'environment'": use filter to get the backside camera with the flash light */
.then(mediaDeviceInfos => mediaDeviceInfos.filter(mediaDeviceInfo => ((mediaDeviceInfo.kind === 'videoinput')/* && mediaDeviceInfo.label.includes("back")*/)))
.then(mediaDeviceInfos => {
console.log("mediaDeviceInfos[0].label: " + mediaDeviceInfos[0].label);
// get the device ID of the backside camera and use it for media stream initialization
deviceConfig.video.deviceId = mediaDeviceInfos[0].deviceId;
navigator.mediaDevices.getUserMedia(deviceConfig)
.then(_gotMedia)
.catch(err => console.error('getUserMedia() failed: ', err));
});
function takePhoto () {
imageCapture.takePhoto()
.then(blob => {
console.log('Photo taken: ' + blob.type + ', ' + blob.size + 'B');
// get URL for blob data and use as source for the image element
const image = document.querySelector('img');
image.src = URL.createObjectURL(blob);
})
.catch(err => console.error('takePhoto() failed: ', err));
}
function _gotMedia (mediastream) {
// use the media stream as source for the video element
const video = document.querySelector('video');
video.srcObject = mediastream;
// create an ImageCapture from the first video track
const track = mediastream.getVideoTracks()[0];
imageCapture = new ImageCapture(track);
// set the image capture options (e.g. flash light, autofocus, ...)
imageCapture.setOptions(imageCaptureConfig)
.catch(err => console.error('setOptions(' + JSON.stringify(imageCaptureConfig) + ') failed: ', err));
}
</script>
Note:
- As of this writing the API is still under development and may change in the future.
- For enabling ImageCapture in Chrome the flag "chrome://flags/#enable-experimental-web-platform-features" has to be set to "true"
- For enabling ImageCapture in Firefox the flag "dom.imagecapture.enabled" in "about:config" has to be set to "true". But "setOptions" is not supported as of this writing!
See also:
- Mediastream Image Capture on GitHub
- NPM module ImageCapture polyfill

- 1,242
- 16
- 23
-
1Four years passed, it is 2021, and this feature seems to be gone. Understandable. `ImageCapture` supports more operations than the underlying track, e.g. turning the torch off and on without asking for permission again. Maybe it's simply impossible to support all devices, so they had to prune it. – Daniel Chin Jul 20 '21 at 07:13
I fixed Daniel's answer and now button works properly on Android phones. IOS is still unsupported.
https://jsfiddle.net/nzw5tv1q/
//have a console on mobile
const consoleOutput = document.getElementById("console");
const log = function (msg) {
consoleOutput.innerText = `${consoleOutput.innerText}\n${msg}`;
console.log(msg);
}
//Test browser support
const SUPPORTS_MEDIA_DEVICES = 'mediaDevices' in navigator;
if (SUPPORTS_MEDIA_DEVICES) {
//Get the environment camera (usually the second one)
navigator.mediaDevices.enumerateDevices().then(devices => {
const cameras = devices.filter((device) => device.kind === 'videoinput');
if (cameras.length === 0) {
log('No camera found on this device.');
}
// Create stream and get video track
navigator.mediaDevices.getUserMedia({
video: {
facingMode: 'environment',
}
}).then(stream => {
const track = stream.getVideoTracks()[0];
//Create image capture object and get camera capabilities
const imageCapture = new ImageCapture(track)
imageCapture.getPhotoCapabilities().then(capabilities => {
//let there be light!
const btn = document.querySelector('.switch');
const torchSupported = !!capabilities.torch || (
'fillLightMode' in capabilities &&
capabilities.fillLightMode.length != 0 &&
capabilities.fillLightMode != 'none'
);
if (torchSupported) {
let torch = false;
btn.addEventListener('click', function (e) {
try {
track.applyConstraints({
advanced: [{
torch: (torch = !torch)
}]
});
} catch (err) {
log(err);
}
});
} else {
log("No torch found");
}
}).catch(log);
}).catch(log);
}).catch(log);
//The light will be on as long the track exists
}
<button class="switch">On / Off</button>
<h2>
Console output
</h2>
<div id="console">
</div>

- 309
- 4
- 6
Here, it is a static class for handling flashlight. You can call flashlightHandler.accessFlashlight()
when the window loads. And then use the flashlightHandler.setFlashlightStatus()
method, passing it true
or false
, as you want the flashlight status.
class flashlightHandler {
static track; //the video track which is used to turn on/off the flashlight
static accessFlashlight() {
//Test browser support
if (!('mediaDevices' in window.navigator)) {
alert("Media Devices not available. Use HTTPS!");
return;
};
//Get the environment camera (usually the second one)
window.navigator.mediaDevices.enumerateDevices().then((devices) => {
const cameras = devices.filter((device) => device.kind === 'videoinput');
if (cameras.length === 0) {
alert("No camera found. If your device has camera available, check permissions.");
return;
};
const camera = cameras[cameras.length - 1];
window.navigator.mediaDevices.getUserMedia({
video: {
deviceId: camera.deviceId
}
}).then((stream) => {
this.track = stream.getVideoTracks()[0];
if (!(this.track.getCapabilities().torch)) {
alert("No torch available.");
};
});
});
}
static setFlashlightStatus(status) {
this.track.applyConstraints({
advanced: [{
torch: status
}]
});
}
}

- 393
- 1
- 4
- 15
I had to implement a similar feature at work and these answers helped me a lot, the thing is I needed to implement it in a React Js web app so I used some of the code provided in older answers to make a react hook to handle the usage of the device's torch (if it is available in the device). I made it into a simple react project in the code sandbox and in case anyone needs something similar in the future this might be useful

- 351
- 5
- 11