Image Capturer - iOS
This guide provides instructions on capturing images of participants from a video stream.
Use it in Video KYC, for example to capture an image of a user holding up their ID for verification.
captureImage()
- By using the
captureImage()function of theParticipantclass, you can capture an image of a participant from their video stream. It works for the local participant, and for a remote participant whose video your device receives. - You have the option to specify the desired width and height in the
captureImage()function; however, these parameters are optional. The image is scaled down to fit within them and keeps its aspect ratio. If not provided, the SDK uses the dimensions of the participant's video. - The
captureImage()function isasync throws, so call it withtry awaitinside aTask. It returns the image in the form of abase64string. - If the image was not captured,
captureImage()throws aVideoSDKError:ERROR_WEBCAM_NOT_ENABLED(3062) when the participant's camera is off, or your device does not receive their video.ERROR_CAPTURE_IMAGE_FAILED(3069) when the capture fails. This error is also sent toonError(error:).
- Swift
extension RoomViewController {
// Button when tapped will capture image
@IBAction func captureImageTapped(_ sender: Any) {
guard let participant = room?.localParticipant else { return }
Task {
do {
let base64Data = try await participant.captureImage(width: 200, height: 200)
print("base64: ", base64Data)
} catch {
print("Image was not captured: \(error)")
}
}
}
}
Capture with flash
- Pass
flash: .ONto light up the scene while the image is captured. The default is.OFF. The SDK uses the torch of the camera in use. A capture with flash takes about half a second longer. - Most front cameras have no torch. For them, set a screen flash with
VideoSDK.setScreenFlash(_:).WhiteOverlayScreenFlashcovers the window in warm white at full brightness while the image is captured. - If there is no torch and no screen flash, the image is captured without flash.
- Flash works only for the local participant. With
flash: .ON,captureImage()throwsERROR_CAPTURE_IMAGE_FAILEDfor a remote participant, and while another capture with flash is running.
- Swift
extension RoomViewController {
// Button when tapped will capture image with flash
@IBAction func captureWithFlashTapped(_ sender: Any) {
// lights up the user's face when the front camera has no torch
VideoSDK.setScreenFlash(WhiteOverlayScreenFlash(window: view.window))
Task {
do {
let base64Data = try await room?.localParticipant.captureImage(flash: .ON)
print("base64: ", base64Data ?? "")
} catch {
print("Image was not captured: \(error)")
}
}
}
}
For a remote participant, the image is taken from the video your device receives from them, so its size depends on the video quality you receive. To capture the image from the remote participant's own camera, ask their device to capture it and send it to you, as shown below.
How to capture image of remote participant on their device?
-
Before proceeding, it's crucial to understand VideoSDK's temporary file storage system and the underlying pubsub mechanism.
-
Here's a breakdown of the steps, using the names Participant A and Participant B for clarity:
Step 1 : Initiate Image Capture Request
- In this step, you have to first send a request to Participant B, whose image you want to capture, using pubsub.
- In order to do that, Participant B has to subscribe to the topic called
IMAGE_CAPTURE. - Here, we will be using the
sendOnlyfield ofPubSubPublishOptions, passed asoptionsto thepublish()method. Therefore, the request will be sent to that participant only.
- Swift
extension RoomViewController {
// Call this, for example from a button, to request an image from a participant
func requestCapture(from participant: Participant) {
let options = PubSubPublishOptions(persist: false, sendOnly: [participant.id])
Task {
do {
try await room?.pubSub.publish(topic: "IMAGE_CAPTURE", message: "Sending Request to capture image", options: options)
} catch {
print("publish error: \(error)")
}
}
}
}
Step 2 : Capture and Upload File
-
To capture image from remote participant [Participant B], we will pick out the request from the
onMessageReceivedevent of thePubSubMessageListener. When a participant receives an image capture request, we will capture image usingcaptureImagefunction of theParticipantclass. -
The captured image is then stored in the VideoSDK's temporary file storage system using the
uploadBase64File()function of theRoomclass. It isasync throwsand returns a uniqueurlof the stored image. -
Next, the
urlis sent back to the participant who initiated the request using theIMAGE_TRANSFERtopic. For this, Participant A must be subscribed to the topicIMAGE_TRANSFER.
- Swift
extension RoomViewController: PubSubMessageListener {
func onMessageReceived(_ message: PubSubMessage) {
if message.topic == "IMAGE_CAPTURE" {
print("received image request")
handleImageCapture(senderId: message.senderId)
return
}
}
}
extension RoomViewController {
func handleImageCapture(senderId: String) {
// Capture the image of the local participant (i.e. Participant B).
guard let room = self.room else {
return
}
Task {
do {
// capture the image.
let image = try await room.localParticipant.captureImage(width: 100, height: 100)
// upload it to the VideoSDK's temporary storage.
let url = try await room.uploadBase64File(base64Data: image, token: "<Your-Token>", fileName: "screenshot.jpeg")
// send url using pubsub back to Participant A.
let options = PubSubPublishOptions(persist: false, sendOnly: [senderId])
try await room.pubSub.publish(topic: "IMAGE_TRANSFER", message: url, options: options)
} catch {
print("Image capture or upload failed: \(error)")
}
}
}
}
Step 3 : Fetch and Display Image
- To fetch the image, you need to be subscribed to the
IMAGE_TRANSFERtopic, receiving theurlassociated with the captured image. Once obtained, use thefetchBase64File()function from theRoomclass to retrieve the file inbase64String format from VideoSDK's temporary storage. It isasync throws.
- Swift
extension RoomViewController: PubSubMessageListener {
func onMessageReceived(_ message: PubSubMessage) {
if message.topic == "IMAGE_CAPTURE" {
print("received image request")
handleImageCapture(senderId: message.senderId)
return
}
// listen for IMAGE_TRANSFER topic
if message.topic == "IMAGE_TRANSFER" {
print("received image response")
Task {
do {
// fetch image from the VideoSDK's temporary storage.
guard let base64Data = try await room?.fetchBase64File(url: message.message, token: "<Your-Token>") else {
return
}
print("base64Data: ", base64Data)
if let data = Data(base64Encoded: base64Data, options: .ignoreUnknownCharacters) {
let image = UIImage(data: data)
//<Display this image or upload to your cloud storage>
}
} catch {
print("retrieval failed: \(error)")
}
}
return
}
}
}
The file stored in the VideoSDK's temporary file storage system will be automatically deleted once the current room comes to an end.
API Reference
The API references for all the methods utilized in this guide are provided below.
Got a Question? Ask us on discord

