Learn how to add a 360-degree product viewer to your web app for an interactive, engaging shopping experience. Easy step-by-step guide!

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 360-Degree Product Viewers Matter
In e-commerce, the gap between digital browsing and physical shopping experiences remains a challenge. While high-quality product images help, nothing beats the ability to pick up a product and examine it from every angle. This is where 360-degree product viewers make a significant difference—they've been shown to increase conversion rates by 30-40% in many implementations I've worked on.
Option 1: JavaScript Libraries (Medium Complexity)
For most businesses, dedicated JavaScript libraries offer the best balance of features, performance, and implementation effort. Here are my top recommendations:
Let's implement a basic 360-degree viewer using ThreeSixty.js:
<!-- Include the ThreeSixty.js library -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/threesixty.min.js"></script>
<!-- Container for our 360 viewer -->
<div id="product-360-viewer" class="product-viewer"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize the 360 viewer
const viewer = new ThreeSixty(
document.getElementById('product-360-viewer'),
{
image: 'path/to/image_%d.jpg', // Format string for image sequence
count: 36, // Number of images in sequence
perRow: 6, // Images per row in sprite sheet (if using sprites)
speed: 100, // Rotation speed
drag: true, // Enable drag to rotate
swipeThreshold: 5, // Pixels needed to trigger swipe
swipeable: true, // Enable touch swipe
keys: true // Enable keyboard controls
}
);
// Preload images and initialize viewer
viewer.init();
});
</script>
Option 2: Third-Party SaaS Solutions (Low Complexity)
If development resources are limited, these platforms provide quick implementation with minimal coding:
Implementation with Sirv as an example:
<!-- Add Sirv's script -->
<script src="https://scripts.sirv.com/sirv.js"></script>
<!-- The viewer container -->
<div class="Sirv" data-src="https://demo.sirv.com/product/spin/bag.spin"></div>
<script>
// Optional configuration
window.SirvOptions = {
spin: {
autospin: {
enabled: true, // Auto-rotation on load
speed: 1500, // Time for full rotation (ms)
direction: "cw", // Clockwise rotation
stopAfter: 2 // Stop after 2 rotations
},
hint: true, // Show interaction hint
mousewheel: true // Enable zoom with mousewheel
}
};
</script>
Option 3: Custom WebGL Implementation (High Complexity)
For ultimate control and advanced features, a custom WebGL solution using Three.js gives you the power to create truly immersive experiences:
<!-- Include Three.js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
<!-- Viewer container -->
<div id="advanced-product-viewer" style="width: 100%; height: 500px;"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Create scene, camera, renderer
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf5f5f5);
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(
document.getElementById('advanced-product-viewer').clientWidth,
document.getElementById('advanced-product-viewer').clientHeight
);
document.getElementById('advanced-product-viewer').appendChild(renderer.domElement);
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Load 3D model (using GLTFLoader)
const loader = new THREE.GLTFLoader();
loader.load(
'path/to/your/product.glb',
function(gltf) {
scene.add(gltf.scene);
// Center the model
const box = new THREE.Box3().setFromObject(gltf.scene);
const center = box.getCenter(new THREE.Vector3());
gltf.scene.position.sub(center);
// Optional: Auto-rotate the model
function animate() {
requestAnimationFrame(animate);
gltf.scene.rotation.y += 0.003;
renderer.render(scene, camera);
}
animate();
}
);
// Add OrbitControls for interaction
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Handle window resize
window.addEventListener('resize', function() {
camera.aspect = document.getElementById('advanced-product-viewer').clientWidth /
document.getElementById('advanced-product-viewer').clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(
document.getElementById('advanced-product-viewer').clientWidth,
document.getElementById('advanced-product-viewer').clientHeight
);
});
});
</script>
Method 1: Professional Photography Setup
For high-quality results, you'll need:
Method 2: 3D Rendering for Digital Products
If your products exist as 3D models:
// Example script for Blender automation (Python)
import bpy
import math
# Set up scene and object
product = bpy.context.active_object
scene = bpy.context.scene
# Configure render settings
scene.render.resolution_x = 1024
scene.render.resolution_y = 1024
scene.render.image_settings.file_format = 'PNG'
# Create 36 images (10-degree increments)
for i in range(36):
# Rotate object
angle = math.radians(i * 10)
product.rotation_euler[2] = angle
# Render and save
scene.render.filepath = f"/path/to/output/image_{i:02d}.png"
bpy.ops.render.render(write_still=True)
Method 3: Smartphone Apps
For budget-conscious options:
Performance Considerations
// Example of lazy-loading high-resolution images after initial load
const viewer = new ThreeSixty(container, {
image: 'path/to/low_res_%d.jpg',
count: 36
});
viewer.init();
// After initial load, switch to high-res images
viewer.onload = function() {
setTimeout(() => {
console.log("Upgrading to high-resolution images...");
viewer.updateImages('path/to/high_res_%d.jpg');
}, 1000); // Wait 1 second after initial load
};
Mobile Optimizations
// Detect mobile and adjust quality accordingly
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
const imageQuality = isMobile() ? 'low' : 'high';
const frameCount = isMobile() ? 18 : 36; // Fewer frames on mobile
const viewer = new ThreeSixty(container, {
image: `path/to/${imageQuality}/%d.jpg`,
count: frameCount
});
Hotspots for Product Features
// Adding interactive hotspots to specific points on the product
viewer.addHotspot({
position: { x: 200, y: 150, frame: 5 }, // Position and which frame it appears on
content: '<div class="hotspot">Titanium Frame<span>Ultra-lightweight, military-grade materials</span></div>',
className: 'product-hotspot'
});
viewer.on('hotspotClick', function(hotspot) {
// Show additional information, maybe open a modal
showFeatureDetails(hotspot.id);
});
Zoom Functionality
// Add zoom capabilities to your viewer
const zoomConfig = {
maxZoom: 3, // Maximum zoom level
zoomStep: 0.5, // Zoom increment per click
initialZoom: 1, // Starting zoom level
zoomInButton: '#zoom-in',
zoomOutButton: '#zoom-out',
onZoom: (level) => {
console.log(`Zoomed to ${level}x`);
// Update UI to show current zoom level
document.getElementById('zoom-level').textContent = `${level}x`;
}
};
viewer.enableZoom(zoomConfig);
Measurements and Scale Reference
// Add measurement tools to your 3D viewer (using Three.js)
function addMeasurementTool(scene, model) {
// Create a visual ruler along the product
const length = getProductLength(model); // Get actual product dimensions
const measureLine = new THREE.Line(
new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(-length/2, 0, 0),
new THREE.Vector3(length/2, 0, 0)
]),
new THREE.LineBasicMaterial({ color: 0x000000 })
);
// Add measurement ticks and labels
for (let i = 0; i <= length; i++) {
if (i % 5 === 0) { // Major tick every 5 units
addMeasurementTick(scene, i - length/2, 0, 0, 0.1, true);
addMeasurementLabel(scene, i - length/2, -0.2, 0, `${i}cm`);
} else { // Minor tick
addMeasurementTick(scene, i - length/2, 0, 0, 0.05, false);
}
}
scene.add(measureLine);
}
Tracking User Interactions
// Tracking user engagement with the 360° viewer
viewer.on('rotation', function(data) {
// Track when user manually rotates the product
gtag('event', 'product_rotate', {
'event_category': 'Product Interaction',
'event_label': 'Product Rotation',
'value': data.currentFrame
});
});
viewer.on('zoom', function(data) {
// Track when user zooms in/out
gtag('event', 'product_zoom', {
'event_category': 'Product Interaction',
'event_label': 'Product Zoom',
'value': data.zoomLevel
});
});
// Track how long users interact with the 360° view
let viewerStartTime;
viewer.on('mousedown', function() {
viewerStartTime = new Date();
});
viewer.on('mouseup', function() {
if (viewerStartTime) {
const interactionTime = new Date() - viewerStartTime;
if (interactionTime > 500) { // Only track meaningful interactions (>0.5s)
gtag('event', 'product_interaction_time', {
'event_category': 'Product Engagement',
'event_label': 'Interaction Duration',
'value': Math.round(interactionTime / 1000) // Convert to seconds
});
}
}
});
Elements Worth Testing
// Simple A/B test implementation
function initializeABTest() {
// Randomly assign users to a test variant
const variant = Math.random() > 0.5 ? 'A' : 'B';
const viewerOptions = {
image: 'path/to/image_%d.jpg',
count: 36
};
if (variant === 'A') {
// Variant A: Auto-rotation on load
viewerOptions.autoplay = {
enabled: true,
speed: 100
};
viewerOptions.showHint = false;
} else {
// Variant B: Static with drag hint
viewerOptions.autoplay = {
enabled: false
};
viewerOptions.showHint = true;
}
// Track which variant was shown
gtag('event', 'ab_test_assignment', {
'event_category': '360_Viewer_Test',
'event_label': `Variant ${variant}`
});
return new ThreeSixty(container, viewerOptions);
}
const viewer = initializeABTest();
One of my clients, a premium watch manufacturer, implemented a 360° viewer and saw these results:
The key success factors were:
Based on my experience implementing 360° viewers for dozens of e-commerce sites, here's the approach I recommend:
The 360° product viewer is one of those rare features that improves both the user experience and business metrics simultaneously. The implementation complexity ranges from a few hours to a few weeks depending on your approach, but even the simplest implementation can yield significant returns on investment.
Explore the top 3 use cases of product 360-degree viewers to boost engagement and sales in your web app.
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.Â