Key takeaways
- Shopify 360 product photography is a sequence of frames the shopper drags through to rotate the product. A common setup is 36 frames at 10-degree intervals.1
- Shopify has native 3D and AR media built into the product media pipeline. It uses Google’s model-viewer and requires a 3D model, not a photo sequence.2
- For flat photo spins, you choose between a 360 spin app or a custom JavaScript viewer. Apps are faster to ship; custom code keeps the markup in your theme.
- Performance is the real risk. A full-resolution 36-frame set can reach 10-20 MB, so compress every frame and lazy-load the viewer.1
- Never lazy-load your LCP image. The first gallery frame the shopper sees should load eagerly.3
360 product photography shows a product from every angle in a single interactive viewer. The shopper drags left or right, or the frames auto-rotate, and the product appears to spin. On a Shopify product page (PDP) this replaces guesswork with a full view of the item.
This guide covers how to capture the frames, prepare the files, and put a spinner on the page. It compares Shopify’s native 3D media, dedicated spin apps, and a custom code viewer, and it treats page speed as a first-class concern.
Why you can trust us
Jacques has over 15 years of development experience and has worked with hundreds of Shopify stores. We built Fudge - an AI-native Shopify page builder and store editor with a 4.8 rating and a Built for Shopify badge. We work with product page media every day.
What is 360-degree product photography?
A 360 spin is not a single photo and not a video. It is an ordered set of still frames, each showing the product rotated by a small step. Software swaps frames as the shopper drags, so the object looks like it turns in place.
The two inputs that matter:
- Frame count. More frames means a smoother spin and a larger download. A common setup is 36 frames at 10-degree intervals.1
- Frame size. A width of roughly 1200-1500px keeps detail without bloating the file.1
This differs from a 3D model, which is a single geometry file the browser renders in real time. Shopify’s native media pipeline handles 3D models and AR, not photo sequences.2 More on that split below.
How to capture 360 image sequences
Turntable and camera
The reliable method is a motorised turntable. Place the product in the centre, fix the camera and lighting, and capture one frame per rotation step. A 10-degree step produces 36 frames.1
Consistency is what sells the effect:
- Keep the camera and lighting locked between frames so only the product moves.
- Centre the product on the turntable so it does not drift across the frame.
- Shoot on a clean, even background so you can mask each frame the same way.
Frame count choices
Fewer frames download faster but spin in visible steps. More frames feel smooth but cost more bytes. 24 frames (15-degree steps) is a lighter option; 36 frames (10-degree steps) is the common middle ground; 72 frames doubles the smoothness and the weight.1
Sourcing without a studio
If you cannot shoot in-house, a product photography studio can deliver a ready sequence. Many provide 36 high-resolution JPEGs per product at a 10-degree interval.1 You still own the file prep and the page work.
File preparation
Raw studio frames are rarely page-ready. Three steps get them there.
- Name frames in order. Use zero-padded numbers (
frame-01.webp…frame-36.webp) so the viewer loads them in sequence. - Crop and align every frame identically. Any drift between frames shows up as a wobble during the spin.
- Compress each frame. This is the step most stores skip, and it is the one that protects page speed.
Modern formats compress better than JPEG. WebP images are around 30% smaller than JPEG at equivalent quality, and AVIF can go further.4 For product photos, a quality setting in the 75-85 range holds detail while cutting weight.4
Do the maths on the full set. Thirty-six frames at 300 KB each is 10.8 MB. The same thirty-six frames at 60-80 KB each is roughly 2-3 MB.1 That difference is the gap between a fast PDP and a slow one.
Three ways to add a 360 spin to a Shopify PDP
There are three routes. They differ in setup effort, where the code lives, and what input they need.
| Method | Input | Where it lives | Best for |
|---|---|---|---|
| Native 3D and AR media | A 3D model (GLB) | Shopify product media | Stores that have or can build 3D models and want AR |
| 360 spin app | A photo sequence | App-injected block or embed | Fastest setup with a photo turntable set |
| Custom JS spin viewer | A photo sequence | Your theme code | Full control over markup, styling, and load behaviour |
Method 1: Shopify native 3D and AR media
Shopify supports 3D models directly in the product media section. Upload a model and the theme renders it with Google’s model-viewer component, so shoppers can rotate and zoom in the browser.2 AR runs through the Shopify-XR library, which powers AR Quick Look on iOS Safari and Scene Viewer on Android.2
In a theme, media is rendered by looping over product.media and applying the matching Liquid filter. For a 3D model that filter is model_viewer_tag.2
The trade-off is the input. Native media wants a 3D model, not a photo spin. If you have turntable photos rather than a modelled asset, this route does not apply. Shopify’s UX guidance also asks that 3D media default to inactive on load and show a progress bar while it loads.5
To add a model without touching code, upload it under Products > (your product) > Media. For related media steps, see how to add video to a Shopify product gallery and how to update product images in Shopify.
Method 2: A 360 spin app
Spin apps take your photo sequence and produce an interactive viewer you place on the PDP. You upload the frames, set controls like drag sensitivity and autoplay, and drop the viewer into the page through the app’s block or embed.
The upside is speed. You skip the code and rely on the app to handle mobile touch and frame swapping. The cost is the usual app trade-off: an added script on your product page, a recurring fee in most cases, and viewer markup you do not own. Check what each app does to your PDP load before committing.
Method 3: A custom JavaScript spin viewer
If you want the viewer in your own theme with no third-party script, a custom spinner is a small amount of code. The idea: preload the frame sequence, then swap the visible frame based on how far the pointer has dragged.
<div id="spin-360" data-frames="36" style="touch-action: pan-y;">
<img
id="spin-frame"
src="/cdn/shop/files/frame-01.webp"
width="1200"
height="1200"
alt="Product 360 view, frame 1"
/>
</div>
<script>
const el = document.getElementById('spin-360')
const img = document.getElementById('spin-frame')
const total = parseInt(el.dataset.frames, 10)
const base = '/cdn/shop/files/frame-'
const pad = (n) => String(n).padStart(2, '0')
let current = 1
let dragging = false
let startX = 0
// Preload frames so swaps are instant once the viewer is active.
const preload = () => {
for (let i = 1; i <= total; i++) {
const pre = new Image()
pre.src = base + pad(i) + '.webp'
}
}
const setFrame = (n) => {
current = ((n - 1 + total) % total) + 1
img.src = base + pad(current) + '.webp'
}
const onMove = (x) => {
if (!dragging) return
const step = Math.round((x - startX) / 8) // pixels per frame
if (step !== 0) {
setFrame(current + step)
startX = x
}
}
el.addEventListener('pointerdown', (e) => {
dragging = true
startX = e.clientX
preload() // load the full set on first interaction, not on page load
})
window.addEventListener('pointermove', (e) => onMove(e.clientX))
window.addEventListener('pointerup', () => (dragging = false))
</script>
Two details make this viewer behave. Pointer events cover mouse and touch in one code path. touch-action: pan-y on the container lets shoppers still scroll the page vertically while dragging the spin horizontally, which matters on mobile.
Preloading on first interaction, rather than on page load, keeps the heavy frame set off the critical path. The first frame is a normal image in the gallery; the rest load only when the shopper reaches for the spin.
Building this by hand means editing theme files. If you would rather describe the viewer in plain language and have on-brand, Shopify-native code generated for you, that is what Fudge does. See also our guide on customising a Shopify product page.
Mobile drag and touch
Mobile is where a spin viewer either works or frustrates. Two conflicts need handling.
- Horizontal drag vs vertical scroll. Without
touch-action: pan-y, a horizontal drag can hijack the page scroll or vice versa. Settingtouch-actiontells the browser which gesture belongs to the spin. - Tap vs drag. A quick tap should not jump the frame. The step calculation above ignores tiny movements, so a tap leaves the frame in place.
Shopify’s own media guidance is to default media to inactive on mobile, so the shopper starts the interaction rather than the page grabbing their first touch.5 Apply the same rule to a custom spinner: show the first frame, and only start swapping once the shopper drags.
Performance: keep the spin off the critical path
A 360 viewer is one of the heaviest things you can put on a PDP. A full-resolution 36-frame set can reach 10-20 MB.1 Handled carelessly, that wrecks your load time. Three rules keep it in check.
1. Compress every frame
Covered above, and it is the biggest lever. Serve WebP or AVIF, which run around 30% smaller than JPEG at the same quality.4 Aim for tens of kilobytes per frame, not hundreds.1
2. Lazy-load the frame set
Only the first frame needs to be in the initial page load. The rest should load when the shopper interacts, or when the viewer scrolls near the viewport. Native loading="lazy" defers off-screen images without any script.3 For a drag-triggered set, load the sequence on first interaction, as the code above does.
3. Protect your LCP
Do not lazy-load your LCP image. web.dev is explicit: do not lazy-load images likely to be in the viewport on load, especially the LCP image.3 On a PDP the first gallery image is usually the LCP element, so let it load eagerly and lazy-load only the extra spin frames. Always set width and height on every frame to avoid layout shift.3
For broader PDP speed work, see how to speed up a Shopify theme and how to lazy-load videos in Shopify, which applies the same defer-until-needed pattern to heavy media.
Apps vs custom code: an honest comparison
Neither route is strictly better. It depends on your team.
A 360 spin app is the right call if you want the viewer live quickly, you do not want to maintain theme code, and you are fine adding one more app script to the PDP. The app handles frame swapping and touch for you.
Custom code is the right call if you want the viewer markup in your own theme, you care about controlling exactly when frames load, and you want to avoid a recurring app fee and an extra third-party script. The cost is the code and its upkeep.
The native 3D route sits apart: it is the best experience where it fits, but it needs a 3D model, not photos, so it is not a drop-in replacement for a photo spin.
Whichever route you pick, the ordering of your gallery still matters for which image loads first. See how to reorder product images in Shopify to make sure your LCP frame is the one shoppers see first.
Summary
360 product photography turns a static gallery into an interactive spin. Capture 24-72 frames on a turntable, compress every frame hard, and put them on the page through native 3D media, a spin app, or a custom JavaScript viewer. The method matters less than the performance discipline: compress the frames, lazy-load the set, and never lazy-load your LCP image.134
If you would rather skip the theme editing and describe what you want in plain language, Fudge generates Shopify-native code for product page media directly in your theme.
FAQ
A common setup is 36 frames captured at 10-degree intervals, which gives a smooth spin without an excessive file size. 24 frames (15-degree steps) is a lighter option, and 72 frames doubles the smoothness at roughly double the weight. Test on mobile to confirm the download stays reasonable.
Shopify natively supports 3D models and AR through the product media pipeline, rendered with Google's model-viewer component. That handles a 3D geometry file rather than a photo turntable sequence. For a spin built from photos you use a 360 spin app or a custom JavaScript viewer in your theme.
It can, because a full-resolution 36-frame set can reach 10-20 MB. Keep it fast by compressing each frame to tens of kilobytes, serving WebP or AVIF, lazy-loading the frame set, and loading only the first frame on initial page load. Never lazy-load your LCP image.
An app is faster to ship and handles frame swapping and touch, at the cost of a recurring fee and an extra script on your PDP. Custom code keeps the viewer in your own theme with full control over when frames load, but you maintain it. Both work; the choice depends on your team.
Set "touch-action: pan-y" on the viewer container so a horizontal drag rotates the product while a vertical swipe still scrolls the page. Use pointer events so mouse and touch share one code path, and default the media to inactive so the shopper starts the spin rather than the page hijacking their first touch.
Use WebP or AVIF, which are around 30% smaller than JPEG at equivalent quality. Shoot at roughly 1200 to 1500px wide, compress at a quality setting around 75 to 85 for photos, and name the frames in zero-padded order so the viewer loads them in sequence.
Footnotes
-
Orbitvu, “How to Add 360 Product Photography to Your Shopify Website.” https://orbitvu.com/blog/how-add-360-product-photography-your-shopify-website ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Shopify, “Support product media.” https://shopify.dev/docs/storefronts/themes/product-merchandising/media/support-media ↩ ↩2 ↩3 ↩4 ↩5
-
web.dev, “Browser-level image lazy loading.” https://web.dev/articles/lazy-loading-images ↩ ↩2 ↩3 ↩4 ↩5
-
web.dev, “Image performance.” https://web.dev/learn/performance/image-performance ↩ ↩2 ↩3 ↩4
-
Shopify, “Product media UX guidelines.” https://shopify.dev/docs/storefronts/themes/product-merchandising/media/media-ux ↩ ↩2