Vinted Browser Extension
Install this Chrome extension to import any Vinted listing into your item wizard with one click.
How It Works
Navigate to any Vinted item listing in Chrome
Click the Maison Archive extension icon and press "Import"
The item wizard opens pre-filled — review, adjust price, and publish
Installation Steps
Create extension folder
Create a folder on your computer called maison-vinted-ext
Save the files below
Copy each file into that folder with the exact filename shown
Open Chrome Extensions
Go to chrome://extensions, enable "Developer mode" (top right toggle)
Load the extension
Click "Load unpacked" and select your maison-vinted-ext folder
Sign in first
Make sure you're signed in to Maison Archive in Chrome, then open a Vinted listing and click the extension icon
Extension Files — Copy & Save
{
"manifest_version": 3,
"name": "Maison Archive — Vinted Importer",
"version": "1.0",
"description": "Import Vinted listings directly into Maison Archive",
"permissions": ["activeTab", "storage", "scripting"],
"host_permissions": ["https://www.vinted.com/*", "https://www.vinted.fr/*", "https://www.vinted.co.uk/*", "https://www.vinted.es/*", "https://www.vinted.de/*"],
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"content_scripts": [
{
"matches": ["https://www.vinted.com/items/*", "https://www.vinted.fr/items/*", "https://www.vinted.co.uk/items/*", "https://www.vinted.es/items/*", "https://www.vinted.de/items/*"],
"js": ["content.js"]
}
]
}// Maison Archive — Vinted content script
function extractVintedData() {
const data = {};
// URL
data.url = window.location.href;
// Try JSON-LD first (most reliable)
const jsonLd = document.querySelector('script[type="application/ld+json"]');
if (jsonLd) {
try {
const parsed = JSON.parse(jsonLd.textContent);
data.title = parsed.name || "";
data.description = parsed.description || "";
data.price = parsed.offers?.price || "";
const img = parsed.image;
data.images = Array.isArray(img) ? img : (img ? [img] : []);
} catch(e) {}
}
// Fallback: scrape DOM
if (!data.title) {
data.title = document.querySelector('[data-testid="item-title"] h1, h1[itemprop="name"]')?.textContent?.trim() ||
document.querySelector('h1')?.textContent?.trim() || "";
}
if (!data.price) {
data.price = document.querySelector('[data-testid="item-price"], [itemprop="price"]')?.getAttribute("content") ||
document.querySelector('[data-testid="item-price"]')?.textContent?.replace(/[^0-9.,]/g, "") || "";
}
// Brand
const brandEl = document.querySelector('[data-testid="item-details-brand"] span, [itemprop="brand"]');
data.brand = brandEl?.textContent?.trim() || "";
// Size
const sizeEl = document.querySelector('[data-testid="item-details-size"] span');
data.size = sizeEl?.textContent?.trim() || "";
// Color
const colorEl = document.querySelector('[data-testid="item-details-color"] span');
data.color = colorEl?.textContent?.trim() || "";
// Condition
const condEl = document.querySelector('[data-testid="item-details-condition"] span, [data-testid="status"]');
data.condition = condEl?.getAttribute("data-testid") || condEl?.textContent?.trim() || "";
// Images fallback
if (!data.images || data.images.length === 0) {
const imgs = Array.from(document.querySelectorAll('[data-testid="item-photo"] img, .item-photos img'));
data.images = imgs.map(i => i.src || i.getAttribute("src")).filter(Boolean).slice(0, 8);
}
return data;
}
// Listen for message from popup
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === "EXTRACT") {
sendResponse(extractVintedData());
}
});<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { width: 320px; font-family: 'Inter', system-ui, sans-serif; background: #FEFCF9; color: #0B0D10; }
.header { background: #0B0D10; padding: 16px 20px; }
.header h1 { font-size: 13px; font-weight: 500; letter-spacing: 0.1em; color: #C7B08B; text-transform: uppercase; }
.header p { font-size: 11px; color: rgba(255,255,255,0.4); margin-top: 2px; }
.body { padding: 20px; }
#status { font-size: 13px; color: #3A3D42; margin-bottom: 16px; line-height: 1.5; }
button { width: 100%; padding: 12px; background: #0B0D10; color: white; border: none; border-radius: 10px; font-size: 13px; cursor: pointer; letter-spacing: 0.05em; }
button:hover { background: #23262B; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.success { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 10px; padding: 12px; font-size: 12px; color: #166534; margin-bottom: 12px; }
.error { background: #fef2f2; border: 1px solid #fecaca; border-radius: 10px; padding: 12px; font-size: 12px; color: #991b1b; margin-bottom: 12px; }
</style>
</head>
<body>
<div class="header">
<h1>Maison Archive</h1>
<p>Vinted Importer</p>
</div>
<div class="body">
<p id="status">Navigate to a Vinted item listing, then click below to import it.</p>
<div id="message"></div>
<button id="importBtn">Import This Listing</button>
</div>
<script src="popup.js"></script>
</body>
</html>const APP_URL = "https://maison.ahurawellness.com"; // e.g. https://myapp.base44.app
document.getElementById("importBtn").addEventListener("click", async () => {
const btn = document.getElementById("importBtn");
const msg = document.getElementById("message");
const status = document.getElementById("status");
btn.disabled = true;
btn.textContent = "Extracting...";
msg.innerHTML = "";
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab.url?.includes("vinted")) {
msg.innerHTML = '<div class="error">Please navigate to a Vinted item listing first.</div>';
btn.disabled = false;
btn.textContent = "Import This Listing";
return;
}
// Extract data from page
const data = await chrome.tabs.sendMessage(tab.id, { type: "EXTRACT" });
if (!data || !data.title) {
msg.innerHTML = '<div class="error">Could not extract data. Make sure you\'re on a product page.</div>';
btn.disabled = false;
btn.textContent = "Import This Listing";
return;
}
// Get stored auth token
const stored = await chrome.storage.local.get("maisonToken");
const token = stored.maisonToken;
if (!token) {
// Open app login to get token
chrome.tabs.create({ url: APP_URL + "/login?ext=1" });
msg.innerHTML = '<div class="error">Please sign in to Maison Archive first. A tab has been opened.</div>';
btn.disabled = false;
btn.textContent = "Import This Listing";
return;
}
btn.textContent = "Sending to Maison Archive...";
const res = await fetch(APP_URL + "/api/functions/vintedImport", {
method: "POST",
headers: { "Content-Type": "application/json", "Authorization": "Bearer " + token },
body: JSON.stringify(data),
});
const result = await res.json();
if (result.success) {
// Store imported data and open the admin item wizard
// We inject a content script to set localStorage, then navigate
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: (data, url) => {
localStorage.setItem("vintedImport", JSON.stringify(data));
window.location.href = url + "/AdminItems?import=1";
},
args: [result.data, APP_URL],
}).catch(() => {
// Fallback: open new tab with data encoded in URL (basic fields only)
chrome.tabs.create({ url: APP_URL + "/AdminItems?import=1" });
});
msg.innerHTML = '<div class="success">✓ Imported! The item wizard has been opened.</div>';
status.textContent = "Item data sent to Maison Archive.";
} else {
throw new Error(result.error || "Unknown error");
}
} catch (e) {
msg.innerHTML = '<div class="error">' + e.message + '</div>';
}
btn.disabled = false;
btn.textContent = "Import This Listing";
});icon.png, save any 48×48px PNG image as icon.png in the same folder. You can use your logo.Auto-fill support in Admin Items
When you import from the extension, the Admin Items page will automatically detect the import data and open the wizard pre-filled. Just go to Admin → Items after clicking import in the extension.