We couldn’t resist the hype any longer – we caved and built an AI tool. We know, total developer cliché. 🙈
Meet "How Do I Look?", a free AI Chrome Extension that lets you virtually try on clothes from any e-commerce site. But here’s the twist: we didn’t just build a cool product — we’re giving away the code for free.
Sure, virtual try-ons are handy (who still shops in-person?!). But the best part is you can use this code to kickstart your next AI-powered project.
How can you do this?
So, go ahead – steal the code, personalize it, and monetize what you create!
Let’s dive into the tech and see how to get started with the extension.
First, check out our GitHub and video demo!
The extension is built with standard web technologies (HTML, CSS, and JavaScript) and follows Chrome's extension architecture. The main components are:
Now, let’s review the user journey so you can start using “How Do I Look?” ASAP (or at least copy the code for your own project 😉).
When you first install the extension, set-up is quick and painless. Configure your API keys, and you’re ready to go!
And don’t worry, the extension checks for these keys automatically on startup.
Manage your API Keys:
document
.getElementById('settingsForm')
.addEventListener('submit', function (e) {
e.preventDefault();
const openAIApiKey = document.getElementById('openAIApiKey').value;
const replicateApiToken = document.getElementById('replicateApiToken').value;
const simpleFileUploadBucketId =
document.getElementById('simpleFileUploadBucketId').value;
localStorage.setItem('openAIApiKey', openAIApiKey);
localStorage.setItem('replicateApiToken', replicateApiToken);
localStorage.setItem('simpleFileUploadBucketId', simpleFileUploadBucketId);
document.getElementById('saveSettings').innerHTML = 'Saved';
setTimeout(() => {
if (openAIApiKey && replicateApiToken) {
hideSettings();
}
}, 1000);
});
Pro Tip: if you release this as a product, you’ll need to do this on the server for all your users.
Once you’ve set-up the extension, it’s easy to get started — you can:
The image handling is managed through an interface that shows visual thumbnails and a quick-access upload button:
<div id="mainContent">
<div id="cachedImages">
<!-- Cached images will be inserted here -->
</div>
<button id="tryOn" disabled>Try On</button>
<div id="loader" class="loader"></div>
<div id="loadingMessage">It may take around 30s to dress up the person</div>
<div id="result"></div>
<input type="file" id="personImage" accept="image/*" style="display: none;">
</div>
Pro Tip: Want to set-up a subscription service and let your users save their looks? Sign-up for Simple File Upload, and you can start monetizing your code in under 5 minutes.
Here’s what happens when you upload an image.
function resizeImage(file, maxWidth) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = function (e) {
const img = new Image();
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const scaleFactor = maxWidth / img.width;
canvas.width = maxWidth;
canvas.height = img.height * scaleFactor;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
resolve(new File([blob], file.name, { type: file.type }));
}, file.type);
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
}
function uploadImageToSimpleFileUpload(imageFile) {
// Files are deleted frequently - to save files sign up
for an account at https://simplefileupload.com/
const bucketId = localStorage.getItem('simpleFileUploadBucketId') ||
'e8557605f1b5ac9b18c913603d29a8c8';
const url = "https://app.simplefileupload.com/api/v1/file"
return resizeImage(imageFile, 500).then((resizedFile) => {
const formData = new FormData();
formData.append('file', resizedFile);
formData.append('bucket_id', bucketId);
// If you want to add tags to the upload to keep everything organized,
you can add them here.
// formData.append('tags', 'user_image');
return fetch(url, {
method: 'POST',
body: formData,
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.data.attributes['ai-url']) {
return data.data.attributes['ai-url'];
} else {
throw new Error('No AI URL in the response');
}
})
.catch(error => {
console.error('Error uploading to Simple File Upload:', error);
throw error;
});
});
}
Pro Tip: This example deletes images every few minutes, but you can try Simple File Upload for free for 7 days if you want to store your images.
When you click "Try On", the extension:
This is handled by the content script:
async function getProductImageFromGPT(htmlContent, openAIApiKey) {
console.log('getProductImageFromGPT', openAIApiKey, !openAIApiKey);
if (!openAIApiKey) {
console.error('OpenAI API key not provided');
return null;
}
const apiUrl = 'https://api.openai.com/v1/chat/completions';
const prompt = `
Analyze the following HTML content and extract the URL of the
main product image.
Look for both <img> tags and CSS background-image properties.
Consider elements and children with class names or IDs
containing words like
'product-image' 'product', 'main', 'featured' etc.
Return only the full URL with commonly used image extensions
(jpg, jpeg, png, webp) of the main product image in JSON format,
with the key "productImageUrl".
If you can't find a product image, return {"productImageUrl": null}.
HTML content:
${htmlContent.substring(
0,
50000
)} // Limiting to few characters to avoid exceeding token limits
`;
try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${openAIApiKey}`,
},
body: JSON.stringify({
model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }],
response_format: {
type: 'json_object',
},
}),
});
const data = await response.json();
const result = JSON.parse(data.choices[0].message.content.trim());
console.log('getProductImageFromGPTresult', result);
return result.productImageUrl;
} catch (error) {
console.error('Error fetching product image from GPT-4o:', error);
return null;
}
}
The magic happens when your photo and the photo of the outfit are processed. 🪄
function performVirtualTryOn(personImageUrl, productImageUrl, currentPageUrl) {
const replicateApiToken = localStorage.getItem('replicateApiToken');
if (!replicateApiToken) {
showError('Replicate API token is missing. Please set it in the settings.');
return;
}
const payload = {
version: "c871bb9b046607b680449ecbae55fd8c6d945e0a1948644bf2361b3d021d3ff4",
input: {
"crop": false,
"seed": 42,
"steps": 30,
"category": "upper_body",
"force_dc": false,
"garm_img": productImageUrl,
"human_img": personImageUrl,
"mask_only": false,
"garment_des": "cute pink top"
}
}
console.log('Sending request to Replicate API:', payload);
fetch('https://api.replicate.com/v1/predictions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${replicateApiToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
response.json().then((data) => {
console.log('Replicate API response:', data);
const getUrl = data.urls.get;
listenForResult(getUrl, productImageUrl, currentPageUrl);
});
})
.catch((error) => {
console.error('Error in virtual try-on process:', error);
showError(`Could not perform virtual try-on. Error: ${error.message}`);
});
}
Pro Tip: You can use different Replicate models for fun! This example is focused on the “upper body,” so it works best for shirts and sweaters.
And that’s a wrap — a complete guide to how we built "How Do I Look?", plus tips on how you can use it to create your own AI-powered project.
Whether you’re building a virtual closet, upgrading your e-commerce site, or launching something new – use this code for your next AI tool. (Seriously, it’s free - go for it!).
And hey, don’t forget to share what you create - we’d love to see what kind of AI tools you design next!
P.S. Huge thanks to Shyjal for sparking this idea – sometimes the best innovations come from building on what inspires us. 💡
P.P.S. Ready to monetize your AI tool? Use Simple File Upload to turn your code into a product. It’s a win-win for everyone. 😉