Build a fully custom virtual try-on experience using Genlook’s backend endpoints
Choose this approach when you want to build a completely bespoke try-on experience. You design the upload screens, loading states, and result displays, while Genlook’s backend quietly handles the AI generation.
The Genlook app block still needs to be installed in your Shopify theme (you can hide the built-in button). We use Shopify’s app proxy to securely authenticate your requests without requiring any API keys, but the proxy must be active.
Here is a minimal, vanilla JavaScript implementation tying the core endpoints together:
async function tryOn(photoFile, productId) { const base = '/apps/proxy_genlook-x/public'; // 1. Ensure the store has credits const credits = await fetch(`${base}/check-credits`).then(r => r.json()); if (!credits.allowed) throw new Error('No generation credits available'); // 2. Upload the user's photo (using our 3-step signed-URL flow) const { uploadUrl, uploadKey } = await fetch(`${base}/prepare-upload`, { method: 'POST', }).then(r => r.json()); await fetch(uploadUrl, { method: 'PUT', headers: { 'Content-Type': 'application/octet-stream' }, body: photoFile, }); const { fileId } = await fetch(`${base}/upload-complete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ uploadKey }), }).then(r => r.json()); // 3. Kick off the AI generation const { jobId } = await fetch(`${base}/fitting-room`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userImageId: fileId, productId }), }).then(r => r.json()); // 4. Poll for the final result for (let i = 0; i < 60; i++) { const status = await fetch(`${base}/generation/${jobId}`).then(r => r.json()); if (status.status === 'COMPLETED') return status.resultImageUrl; if (status.status === 'FAILED') throw new Error(status.errorMessage); // Wait 2 seconds before polling again await new Promise(resolve => setTimeout(resolve, 2000)); } throw new Error('The generation request timed out');}
If you’re using our SDK alongside your custom endpoints, you can use Genlook.cabin.fetch(url, options) instead of manually constructing the base proxy path. Read more about it in the Custom Button guide.