Skip to main content
Version: 4.x.x

Sending Virtual Gifts - iOS

Virtual gifting allows viewers to support hosts or speakers during a livestream by sending them digital tokens or "gifts." These gifts can be visually animated and even linked to leaderboards or reward systems.

This guide explains how to implement virtual gifting using your backend server together with VideoSDK PubSub.

How It Works​

  1. User Action: A viewer taps on a gift button to send a virtual gift to the host.

  2. Server Verification:

    • A request is made to your business backend to process the gift.
    • The server authenticates the user, checks their wallet balance, deducts the gift value, and returns a success response.
  3. Event Broadcast: Upon success, the client publishes a PubSub message to inform everyone in the room (host + other viewers) that a gift has been sent. Clients can then visually show an animation or notification.

Backend Responsibility​

Your backend plays a central role in verifying, validating, and processing gift transactions. It should:

  • Authenticate the request (token/session)
  • Verify if the user has sufficient balance
  • Deduct the gift cost
  • Store the transaction in a database (optional but recommended)
  • Respond with success or failure

Frontend Implementation​

  • Sending a Gift (Client to Backend + PubSub)

    publish() takes the message as a String, so the gift details go in its payload. It is async throws, so call it with try await inside a Task.

import UIKit
import VideoSDKRTC

class GiftSenderViewController: UIViewController {
var room: Room!

func sendGift(giftType: String, senderId: String, hostId: String) {
let url = URL(string: "https://your-api.com/send-gift")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body: [String: Any] = [
"senderId": senderId,
"hostId": hostId,
"giftType": giftType
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let success = json["success"] as? Bool,
success
else {
DispatchQueue.main.async {
self.showAlert(message: "Gift could not be sent.")
}
return
}

// Publish the gift event
let payload: [String: Any] = [
"giftType": giftType,
"from": senderId,
"to": hostId
]
Task {
do {
try await self.room.pubSub.publish(topic: "GIFT", message: giftType, options: PubSubPublishOptions(persist: true), payload: payload)
} catch {
print("Failed to publish the gift event: \(error)")
}
}
}
task.resume()
}

func showAlert(message: String) {
let alert = UIAlertController(title: "Gift", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}
  • Displaying the Gift (All Clients)
import UIKit
import VideoSDKRTC

class GiftReceiverViewController: UIViewController, PubSubMessageListener {
var room: Room! // Assume this is your current room instance
var gifts: [[String: Any]] = []

override func viewDidLoad() {
super.viewDidLoad()
// Show this screen after you join the room. subscribe() throws before that.
Task {
do {
try await room.pubSub.subscribe(topic: "GIFT", listener: self)
} catch {
print("Failed to subscribe to gifts: \(error)")
}
}
}

func onMessageReceived(_ message: PubSubMessage) {
let giftData = message.payload
gifts.append(giftData)
DispatchQueue.main.async {
self.displayGiftToast(giftData: giftData)
}
}

func displayGiftToast(giftData: [String: Any]) {
guard
let from = giftData["from"] as? String,
let to = giftData["to"] as? String,
let giftType = giftData["giftType"] as? String
else { return }

let toast = UILabel()
toast.text = "🎁 \(from) sent a \(giftType) to \(to)"
toast.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toast.textColor = .white
toast.textAlignment = .center
toast.frame = CGRect(x: 20, y: self.view.frame.height - 100, width: self.view.frame.width - 40, height: 50)
toast.alpha = 0
self.view.addSubview(toast)

UIView.animate(withDuration: 0.5, animations: {
toast.alpha = 1
}) { _ in
UIView.animate(withDuration: 0.5, delay: 2, options: [], animations: {
toast.alpha = 0
}) { _ in
toast.removeFromSuperview()
}
}
}
}

API Reference​

The API references for all the methods and events utilized in this guide are provided below.

Got a Question? Ask us on discord