Membangun QR Code Scanner Berbasis WebRTC Menggunakan Instascan.js

Pada tutorial ini, kita akan membuat sebuah aplikasi web yang dirancang khusus agar berjalan optimal di perangkat seluler. Aplikasi ini mampu mendeteksi dan memindai kode QR secara langsung melalui kamera, lalu menampilkan hasil atau isi dari kode tersebut kepada pengguna secara real-time.
Untuk fitur pemindaiannya, kita akan memanfaatkan Instascan.js, yaitu library JavaScript berbasis HTML5 yang memanfaatkan teknologi WebRTC untuk mengakses kamera perangkat. Library ini menyediakan API yang memudahkan kita dalam mengaktifkan kamera, memilih perangkat kamera yang tersedia, serta menangani event saat kode QR berhasil dipindai.
Kita akan mengikuti langkah-langkah ini:
- Membuat struktur HTML dasar
- Menambahkan pustaka Instascan
- Menambahkan elemen video
- Menambahkan area tampilan untuk kode QR yang dipindai
- Menginisialisasi pemindai dengan JavaScript
- Menangani peristiwa pemindaian
- Mengakses kamera
- Menambahkan gaya
- Menjalankan aplikasi
Langkah 1 : Buat Struktur HTML Dasar
Langkah pertama, siapkan struktur dasar dokumen HTML5 seperti biasa. Setelah itu, tambahkan elemen pemilih kamera di dalam bagian <head> <body> agar pengguna dapat menentukan kamera mana yang ingin digunakan. Fitur ini sangat berguna terutama pada perangkat seluler, karena memungkinkan pengguna beralih antara kamera depan dan kamera belakang sesuai kebutuhan saat melakukan pemindaian QR code.
<!DOCTYPE html>
<html>
<head>
<title>Instascan QR Code Scanner</title>
</head>
<body>
<h1>Instascan QR Code Scanner</h1>
<select id="cameraSelector" style="display:none;">
<option value="">Select Camera...</option>
</select>
</body>
</html>Dalam contoh ini, kita akan menyertakan JavaScript dan CSS dalam file HTML. Namun, Anda bebas memisahkannya ke dalam file eksternal.
Langkah 2: Tambahkan library Instascan
Untuk mulai menggunakan Instascan.js di dalam aplikasi web, Anda bisa menambahkannya melalui CDN dengan menyisipkan script pada bagian <head> dokumen HTML. Cara ini praktis karena Anda tidak perlu mengunduh file library secara manual cukup tautkan sumber CDN, dan library siap digunakan di proyek Anda.
<script
type="text/javascript"
src="https://rawcdn.githack.com/schmich/instascan-builds/master/instascan.min.js"
></script>Jika Anda tidak ingin menggunakan CDN, alternatifnya adalah mengunduh file instascan.min.js langsung dari halaman rilis repositori resmi Instascan.js. Setelah diunduh, simpan file tersebut di dalam direktori proyek Anda, lalu sesuaikan pemanggilan script pada HTML dengan mengubah atribut src menjadi src="instascan.min.js".
Dengan cara ini, library akan dimuat secara lokal, sehingga aplikasi tetap dapat berjalan tanpa bergantung pada koneksi ke CDN eksternal.
Langkah 3: Tambahkan elemen video
Selanjutnya, buat elemen <video> untuk menampilkan tampilan kamera. Tambahkan atribut autoplay playsinline agar tampilan dimulai secara otomatis dan berfungsi di perangkat seluler:<video id="preview" autoplay playsinline></video>
Langkah 4: Tambahkan area tampilan untuk kode QR yang dipindai
Di bawah elemen video (preview kamera), tambahkan sebuah judul sebagai penanda bagian hasil pemindaian. Setelah itu, siapkan elemen <div> yang akan berfungsi sebagai wadah untuk menampilkan daftar kode QR yang berhasil dipindai.
Struktur ini membantu pengguna melihat riwayat hasil pemindaian secara lebih rapi dan terorganisir.
<h2>Scanned QR Codes:</h2>
<div id="scannedList">
<p style="color: #666;">No codes scanned yet...</p>
</div>Langkah 5: Inisialisasi Scanner dengan JavaScript
Selanjutnya, tambahkan tag <script> untuk menuliskan logika JavaScript aplikasi. Di dalamnya, ambil referensi ke beberapa elemen penting, yaitu elemen preview (video), daftar hasil pemindaian (scannedList), dan pemilih kamera (cameraSelector).
Setelah itu, buat instance scanner baru dan teruskan elemen video sebagai parameter. Dengan cara ini, library dapat menggunakan elemen tersebut untuk menampilkan tampilan kamera sekaligus memproses pemindaian QR code secara langsung.
const videoElement = document.getElementById("preview");
const scannedList = document.getElementById("scannedList");
const cameraSelector = document.getElementById("cameraSelector");
const scanner = new Instascan.Scanner({
video: videoElement,
mirror: false
});
let cameras = [];Langkah 6: Menangani Event Pemindaian
Tambahkan event listener yang akan dipicu setiap kali kode QR berhasil terdeteksi oleh kamera. Event ini bertugas mengelola dan menampilkan hasil pemindaian ke dalam daftar yang sudah disiapkan sebelumnya.
Pada contoh implementasi, setiap kali proses scan berhasil, sistem akan melakukan beberapa hal berikut:
- Mengambil waktu saat ini sebagai penanda kapan kode dipindai.
- Membuat elemen <div> baru yang diberi gaya menyerupai item daftar.
- Menambahkan isi hasil pemindaian beserta stempel waktunya ke dalam elemen tersebut.
- Menghapus teks placeholder saat pemindaian pertama berhasil dilakukan.
- Menyisipkan item baru tersebut ke bagian paling atas daftar, sehingga hasil terbaru selalu tampil di posisi teratas.
Dengan pendekatan ini, pengguna dapat melihat riwayat pemindaian secara real-time dan terurut dengan jelas.
scanner.addListener("scan", (content) => {
const timestamp = new Date().toLocaleTimeString();
const item = document.createElement("div");
item.className = "scanned-item";
item.innerHTML = `<strong>${content}</strong><span class="timestamp">${timestamp}</span>`;
if (scannedList.querySelector("p")) {
scannedList.innerHTML = "";
}
scannedList.insertBefore(item, scannedList.firstChild);
});Langkah 7: Akses kamera
Selanjutnya, tambahkan listener untuk menangani pergantian kamera.
cameraSelector.addEventListener("change", (e) => {
const cameraId = e.target.value;
const selectedCamera = cameras.find(c => c.id === cameraId);
if (selectedCamera) {
scanner.start(selectedCamera);
}
});Sekarang Anda dapat menggunakan API Instascan untuk mendapatkan kamera yang tersedia, lalu mulai memindai:
Instascan.Camera.getCameras()
.then((availableCameras) => {
cameras = availableCameras;
if (cameras.length === 0) {
alert("No cameras found.");
return;
}
// Populate dropdown
cameras.forEach((camera, index) => {
const option = document.createElement("option");
option.value = camera.id;
option.text = camera.name || `Camera ${index + 1}`;
cameraSelector.appendChild(option);
});
// Show selector if multiple cameras
if (cameras.length > 1) {
cameraSelector.style.display = "block";
}
// Try to find and start back camera
let backCamera = null;
// Try multiple methods to find back camera
for (let camera of cameras) {
const name = camera.name.toLowerCase();
// Check for common back camera indicators
if (name.includes("back") ||
name.includes("rear") ||
name.includes("environment") ||
name.includes("后") || // Chinese
name.includes("trasera")) { // Spanish
backCamera = camera;
break;
}
}
// If no back camera found, try the last camera (often the back one on mobile)
if (!backCamera && cameras.length > 1) {
backCamera = cameras[cameras.length - 1];
}
// Fallback to first camera
const cameraToUse = backCamera || cameras[0];
// Set dropdown to selected camera
cameraSelector.value = cameraToUse.id;
// Start scanning
scanner.start(cameraToUse);
console.log("Available cameras:", cameras.map(c => c.name));
console.log("Using camera:", cameraToUse.name);
})
.catch((err) => {
console.error("Camera error:", err);
alert("Could not access camera. Please check permissions.");
});Persyaratan HTTPS: Akses kamera WebRTC hanya berfungsi pada:- situs web https://
- localhost (untuk pengujian)
- Namun tidak di http:// (kecuali localhost)
- Izin browser: Pengguna harus memberikan izin akses kamera.
- Dukungan browser: Membutuhkan browser yang kompatibel dengan WebRTC (semua browser modern, kecuali IE)
- Konteks keamanan: Beberapa fitur mungkin tidak berfungsi di dalam iframe atau konteks tertentu.
Langkah 8 (opsional): Tambahkan gaya
Untuk meningkatkan tampilan aplikasi, Anda dapat menambahkan CSS di bagian <head>:
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
#preview {
width: 100%;
max-width: 400px;
height: auto;
border: 2px solid #ccc;
border-radius: 5px;
}
#cameraSelector {
margin: 10px 0;
padding: 8px;
font-size: 16px;
}
#scannedList {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #f9f9f9;
max-width: 400px;
}
.scanned-item {
padding: 8px;
margin: 5px 0;
background-color: white;
border-left: 3px solid #4CAF50;
word-break: break-all;
}
.timestamp {
font-size: 0.8em;
color: #666;
margin-left: 5px;
}
</style>File index.html final Anda akan terlihat seperti ini:
<!DOCTYPE html>
<html>
<head>
<title>Instascan QR Code Scanner</title>
<script
type="text/javascript"
src="https://rawcdn.githack.com/schmich/instascan-builds/master/instascan.min.js"
></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
#preview {
width: 100%;
max-width: 400px;
height: auto;
border: 2px solid #ccc;
border-radius: 5px;
}
#cameraSelector {
margin: 10px 0;
padding: 8px;
font-size: 16px;
}
#scannedList {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #f9f9f9;
max-width: 400px;
}
.scanned-item {
padding: 8px;
margin: 5px 0;
background-color: white;
border-left: 3px solid #4CAF50;
word-break: break-all;
}
.timestamp {
font-size: 0.8em;
color: #666;
margin-left: 5px;
}
</style>
</head>
<body>
<h1>Instascan QR Code Scanner</h1>
<select id="cameraSelector" style="display:none;">
<option value="">Select Camera...</option>
</select>
<video id="preview" autoplay playsinline></video>
<h2>Scanned QR Codes:</h2>
<div id="scannedList">
<p style="color: #666;">No codes scanned yet...</p>
</div>
<script>
const videoElement = document.getElementById("preview");
const scannedList = document.getElementById("scannedList");
const cameraSelector = document.getElementById("cameraSelector");
const scanner = new Instascan.Scanner({
video: videoElement,
mirror: false
});
let cameras = [];
scanner.addListener("scan", (content) => {
const timestamp = new Date().toLocaleTimeString();
const item = document.createElement("div");
item.className = "scanned-item";
item.innerHTML = `<strong>${content}</strong><span class="timestamp">${timestamp}</span>`;
if (scannedList.querySelector("p")) {
scannedList.innerHTML = "";
}
scannedList.insertBefore(item, scannedList.firstChild);
});
cameraSelector.addEventListener("change", (e) => {
const cameraId = e.target.value;
const selectedCamera = cameras.find(c => c.id === cameraId);
if (selectedCamera) {
scanner.start(selectedCamera);
}
});
Instascan.Camera.getCameras()
.then((availableCameras) => {
cameras = availableCameras;
if (cameras.length === 0) {
alert("No cameras found.");
return;
}
cameras.forEach((camera, index) => {
const option = document.createElement("option");
option.value = camera.id;
option.text = camera.name || `Camera ${index + 1}`;
cameraSelector.appendChild(option);
});
if (cameras.length > 1) {
cameraSelector.style.display = "block";
}
let backCamera = null;
for (let camera of cameras) {
const name = camera.name.toLowerCase();
if (name.includes("back") ||
name.includes("rear") ||
name.includes("environment") ||
name.includes("后") ||
name.includes("trasera")) {
backCamera = camera;
break;
}
}
if (!backCamera && cameras.length > 1) {
backCamera = cameras[cameras.length - 1];
}
const cameraToUse = backCamera || cameras[0];
cameraSelector.value = cameraToUse.id;
scanner.start(cameraToUse);
console.log("Available cameras:", cameras.map(c => c.name));
console.log("Using camera:", cameraToUse.name);
})
.catch((err) => {
console.error("Camera error:", err);
alert("Could not access camera. Please check permissions.");
});
</script>
</body>
</html>Langkah 9: Menjalankan Aplikasi
Kini, aplikasi pemindai QR code berbasis WebRTC yang telah Anda bangun sudah siap digunakan. Buka file proyek di browser, izinkan akses kamera saat diminta, lalu arahkan kamera ke beberapa kode QR untuk menguji fungsinya.
Jika seluruh langkah sebelumnya telah dilakukan dengan benar, hasil pemindaian akan langsung muncul secara real-time di daftar yang telah disediakan.
Kesimpulan
Demikian tutorial tentang cara membangun aplikasi web pemindai QR code sederhana menggunakan HTML5 dan library Instascan.js. Dengan memanfaatkan teknologi kamera berbasis browser, Anda dapat membuat sistem pemindaian yang berjalan langsung tanpa perlu instalasi aplikasi tambahan.
Penggunaan library open-source seperti ini sangat cocok untuk kebutuhan prototipe, pembelajaran, maupun proyek pribadi. Proses implementasinya relatif cepat dan fleksibel, sehingga memudahkan developer dalam melakukan eksperimen atau pengembangan awal.
Namun, untuk skala bisnis atau aplikasi produksi yang lebih kompleks, pendekatan ini perlu dipertimbangkan secara matang. Pengelolaan performa, keamanan, kompatibilitas perangkat, serta pemeliharaan jangka panjang menjadi tantangan tersendiri apabila tidak didukung oleh solusi dengan dukungan teknis yang memadai.
Semoga tutorial ini bermanfaat dan dapat menjadi langkah awal Anda dalam mengembangkan aplikasi berbasis kamera di web.


