Learn how to add dynamic QR code generation to your mobile app with this easy, step-by-step guide for seamless integration.

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Why Dynamic QR Codes Matter
Static QR codes are like permanent tattoos—once created, they point to the same information forever. Dynamic QR codes, on the other hand, are like digital chameleons that can change their destination without changing their appearance. For business applications, this distinction is crucial.
The most sustainable approach for implementing dynamic QR codes involves three distinct layers:
Think of this as a restaurant: your users see the dining area (frontend), the kitchen prepares the meals (backend service), and the chef's cooking techniques are the QR generation engine.
You have two options here:
Option A: Use a third-party QR service
Services like QRCode Monkey API, QR Code Generator API, or GoQR.me offer ready-made solutions with tracking capabilities.
Option B: Create your own generator
For React Native apps:
// Install the required packages
// npm install react-native-qrcode-svg
import QRCode from 'react-native-qrcode-svg';
// Then in your component:
const MyQRCode = ({ value, size }) => (
<QRCode
value={value} // This will be your short URL that points to your backend
size={size || 200}
backgroundColor="white"
color="black"
/>
);
For native iOS:
// In your ViewController or relevant class
import CoreImage.CIFilterBuiltins
func generateQRCode(from string: String) -> UIImage? {
let context = CIContext()
let filter = CIFilter.qrCodeGenerator()
// Set the message content
let data = string.data(using: .utf8)
filter.setValue(data, forKey: "inputMessage")
// Configure error correction - higher levels make QR codes more resilient but denser
filter.setValue("M", forKey: "inputCorrectionLevel") // L, M, Q, H (low to high)
// Get the output image
if let outputImage = filter.outputImage {
if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
return UIImage(cgImage: cgImage)
}
}
return nil
}
For native Android:
// You'll need to add ZXing library to your build.gradle:
// implementation 'com.google.zxing:core:3.4.1'
import android.graphics.Bitmap
import com.google.zxing.BarcodeFormat
import com.google.zxing.MultiFormatWriter
import com.google.zxing.common.BitMatrix
fun generateQRCode(content: String, width: Int, height: Int): Bitmap? {
try {
val bitMatrix: BitMatrix = MultiFormatWriter().encode(
content, BarcodeFormat.QR_CODE, width, height
)
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
for (x in 0 until width) {
for (y in 0 until height) {
bitmap.setPixel(x, y, if (bitMatrix[x, y]) 0xFF000000.toInt() else 0xFFFFFFFF.toInt())
}
}
return bitmap
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
This is where the real magic of dynamic QR codes happens. Your backend needs to:
Here's a simplified Node.js Express example of what this might look like:
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const app = express();
// In-memory storage (use a database in production)
const qrCodes = {};
const scanEvents = [];
// Create a new dynamic QR code
app.post('/api/qr-codes', (req, res) => {
const { destinationUrl, ownerId, metadata } = req.body;
const id = uuidv4().substring(0, 8); // Short unique ID
qrCodes[id] = {
id,
destinationUrl,
ownerId,
metadata,
createdAt: new Date(),
updatedAt: new Date()
};
// The URL to encode in the QR code
const qrUrl = `https://yourdomain.com/q/${id}`;
res.json({
id,
qrUrl,
// You could generate the QR code image here if not doing it client-side
});
});
// Update a QR code's destination
app.put('/api/qr-codes/:id', (req, res) => {
const { id } = req.params;
const { destinationUrl, metadata } = req.body;
if (!qrCodes[id]) {
return res.status(404).json({ error: 'QR code not found' });
}
qrCodes[id].destinationUrl = destinationUrl;
if (metadata) qrCodes[id].metadata = { ...qrCodes[id].metadata, ...metadata };
qrCodes[id].updatedAt = new Date();
res.json(qrCodes[id]);
});
// Handle QR code redirects
app.get('/q/:id', (req, res) => {
const { id } = req.params;
if (!qrCodes[id]) {
return res.status(404).send('QR code not found');
}
// Record scan event
scanEvents.push({
qrId: id,
timestamp: new Date(),
userAgent: req.headers['user-agent'],
ipAddress: req.ip,
// Add other relevant tracking data
});
// Redirect to the destination URL
res.redirect(qrCodes[id].destinationUrl);
});
// Get analytics for a QR code
app.get('/api/qr-codes/:id/analytics', (req, res) => {
const { id } = req.params;
if (!qrCodes[id]) {
return res.status(404).json({ error: 'QR code not found' });
}
const qrScans = scanEvents.filter(event => event.qrId === id);
res.json({
qrCode: qrCodes[id],
totalScans: qrScans.length,
scans: qrScans
});
});
app.listen(3000, () => {
console.log('QR code service running on port 3000');
});
The frontend integration typically involves:
React Native Example:
import React, { useState } from 'react';
import { View, TextInput, Button, StyleSheet, Alert } from 'react-native';
import QRCode from 'react-native-qrcode-svg';
import api from '../services/api'; // Your API client
const QRCodeGenerator = () => {
const [destination, setDestination] = useState('');
const [qrData, setQRData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const generateQRCode = async () => {
if (!destination) {
Alert.alert('Error', 'Please enter a destination URL');
return;
}
setIsLoading(true);
try {
const response = await api.post('/api/qr-codes', {
destinationUrl: destination,
metadata: {
purpose: 'marketing',
campaign: 'summer_2023'
}
});
setQRData(response.data);
} catch (error) {
Alert.alert('Error', 'Failed to generate QR code');
console.error(error);
} finally {
setIsLoading(false);
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Enter destination URL"
value={destination}
onChangeText={setDestination}
/>
<Button
title="Generate QR Code"
onPress={generateQRCode}
disabled={isLoading}
/>
{qrData && (
<View style={styles.qrContainer}>
<QRCode
value={qrData.qrUrl}
size={200}
backgroundColor="white"
color="black"
/>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
alignItems: 'center',
},
input: {
width: '100%',
height: 50,
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 5,
marginBottom: 20,
paddingHorizontal: 10,
},
qrContainer: {
marginTop: 30,
padding: 20,
backgroundColor: '#f9f9f9',
borderRadius: 10,
alignItems: 'center',
}
});
export default QRCodeGenerator;
1. Customization Options
Allow users to customize QR codes with:
2. Smart Redirection Logic
// On your backend redirect handler
app.get('/q/:id', (req, res) => {
const { id } = req.params;
const userAgent = req.headers['user-agent'];
const qrCode = qrCodes[id];
if (!qrCode) {
return res.status(404).send('QR code not found');
}
// Record scan event
recordScan(id, req);
// Determine platform for smart redirection
const isIOS = /iPhone|iPad|iPod/i.test(userAgent);
const isAndroid = /Android/i.test(userAgent);
// Redirect based on platform, time of day, location, or other parameters
if (isIOS && qrCode.metadata.iosUrl) {
return res.redirect(qrCode.metadata.iosUrl);
} else if (isAndroid && qrCode.metadata.androidUrl) {
return res.redirect(qrCode.metadata.androidUrl);
} else {
return res.redirect(qrCode.destinationUrl);
}
});
3. Comprehensive Analytics
1. QR Code Density
The more data you put in a QR code, the denser and harder to scan it becomes. Always use short URLs in your QR codes that redirect through your backend.
2. Error Correction Levels
QR codes support different error correction levels (L, M, Q, H) which determine how much damage a code can sustain while remaining scannable:
Higher correction levels make your code more resilient but also denser. For branded QR codes with logos, use at least Q or H level.
3. Testing Across Devices
Always test your QR codes on multiple devices and in various lighting conditions. Some older devices may struggle with highly customized or dense QR codes.
1. On-demand vs. Pre-generated
For mobile apps, consider whether to generate QR codes on-demand or pre-generate and cache them:
2. Backend Scalability
Your redirection backend is a critical path in the QR code experience. Ensure it's:
Dynamic QR codes aren't just a technical feature—they're a business strategy. They bridge physical and digital experiences while providing invaluable data about how users interact with your brand in the real world.
The implementation complexity is justified by the long-term flexibility: you can start with simple redirection and progressively enhance your QR system with analytics, personalization, and campaign tracking as your needs evolve.
Remember: The QR code itself is just the visible tip of the iceberg. The real value comes from the dynamic infrastructure you build underneath it, turning simple black-and-white squares into powerful, adaptive tools for customer engagement.
Explore the top 3 dynamic QR code use cases to boost your mobile app’s functionality and user engagement.
From startups to enterprises and everything in between, see for yourself our incredible impact.
Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.Â