Introduction
The ecomvis API lets you add AI-powered product search to any e-commerce store. Your product catalog is indexed once — after that, every search returns ranked results in milliseconds.
The API is RESTful, uses JSON bodies, and is authenticated with an API key per store. All requests must be made over HTTPS.
https://ecomvis.com/api/All endpoints are relative to this base.
Supported search modes
Text search
Natural language queries — "red summer dress under $50"
Image search
Upload a photo or pass an image URL to find visually similar products
Voice search
Send an audio recording; ecomvis transcribes and searches in one step
Authentication
Every request must include your store's API key. You can pass it in three ways — the header is preferred for server-side usage:
| Method | Where | Value |
|---|---|---|
| X-API-Key | Request header | X-API-Key: your_api_key |
| Authorization | Request header | Authorization: Bearer your_api_key |
| api_key | Query string or POST body | ?api_key=your_api_key |
Find your API key in Dashboard → Settings → API Key after creating a store and training its index.
Quick start
Create an account & add your store
Sign up, go to Dashboard → Add Website, and paste your store URL.
Train your product index
ecomvis crawls your product feed and builds a semantic search index. Training typically takes a few minutes for up to 10 000 products.
Copy your API key
Dashboard → Settings → API Key. The key is unique per store.
Make your first search call
Use the text search endpoint below — your first result should appear in under 200 ms.
curl -X POST https://ecomvis.com/api/search/text/ \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "red summer dress", "top_k": 5}'
Text search
Search your product catalog using a natural-language query string. The AI model understands synonyms, intent, and context — not just exact keyword matches.
Request body
| Field | Type | Description |
|---|---|---|
| queryrequired | string | Natural language product description. Min 2 characters. |
| top_koptional | integer | Number of results to return. Default 5. Max 20. |
Example
POST /api/search/text/ X-API-Key: your_api_key Content-Type: application/json { "query": "red summer dress", "top_k": 5 }
{
"results": [
{
"name": "Floral Red Midi",
"product_url": "https://...",
"score": 0.94
},
...
]
}
Code examples
// Text search example const res = await fetch('https://ecomvis.com/api/search/text/', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'red summer dress', top_k: 5 }), }); const data = await res.json(); console.log(data.results);
import requests
resp = requests.post(
"https://ecomvis.com/api/search/text/",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"query": "red summer dress", "top_k": 5},
)
results = resp.json()["results"]
$ch = curl_init('https://ecomvis.com/api/search/text/'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'X-API-Key: YOUR_API_KEY', 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'query' => 'red summer dress', 'top_k' => 5, ]), ]); $data = json_decode(curl_exec($ch), true);
Image search
Find products that look visually similar to a photo. Pass either an image URL (JSON body) or upload a file directly (multipart form).
Option A — image URL (JSON)
| Field | Type | Description |
|---|---|---|
| image_urlrequired | string | Publicly accessible URL of the image. |
| top_koptional | integer | Results to return. Default 5. |
Option B — file upload (multipart)
| Field | Type | Description |
|---|---|---|
| imagerequired | file | Image file. JPEG, PNG, WebP supported. Max 10 MB. |
| top_koptional | integer | Results to return. Default 5. |
Examples
curl -X POST https://ecomvis.com/api/search/image/ \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url":"https://example.com/dress.jpg","top_k":5}'
// fileInput is an <input type="file"> element const form = new FormData(); form.append('image', fileInput.files[0]); form.append('top_k', '5'); const res = await fetch('https://ecomvis.com/api/search/image/', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY' }, body: form, }); const data = await res.json();
import requests with open("product.jpg", "rb") as f: resp = requests.post( "https://ecomvis.com/api/search/image/", headers={"X-API-Key": "YOUR_API_KEY"}, files={"image": f}, data={"top_k": 5}, ) results = resp.json()["results"]
Voice search
Send an audio recording and receive ranked product results in one call. ecomvis transcribes the audio then runs the semantic search automatically.
Request — multipart form
| Field | Type | Description |
|---|---|---|
| audiorequired | file | Audio recording. WAV, MP3, WebM, OGG supported. Max 25 MB. |
| top_koptional | integer | Results to return. Default 5. |
Example — JavaScript MediaRecorder
// Record from microphone, then search const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const recorder = new MediaRecorder(stream); const chunks = []; recorder.ondataavailable = e => chunks.push(e.data); recorder.onstop = async () => { const blob = new Blob(chunks, { type: 'audio/webm' }); const form = new FormData(); form.append('audio', blob, 'query.webm'); form.append('top_k', '5'); const res = await fetch('https://ecomvis.com/api/search/voice/', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY' }, body: form, }); const data = await res.json(); console.log(data.results); }; recorder.start(); setTimeout(() => recorder.stop(), 3000); // record 3 seconds
Status
Check the current state of your store's search index and remaining quota.
curl https://ecomvis.com/api/status/ \
-H "X-API-Key: YOUR_API_KEY"
{
"website": "mystore.com",
"is_trained": true,
"searches_today": 142,
"monthly_limit": 10000,
"plan": "Starter"
}
Vanilla JS / Plain HTML
The quickest way to add ecomvis to any website. Drop the script tag in your HTML and initialise the widget — no build step required.
<!-- Place before </body> --> <script src="https://ecomvis.com/static/js/widget.js"></script> <script> EcomvisWidget.init({ apiKey: 'YOUR_API_KEY', position: 'bottom-right', // or 'bottom-left' placeholder: 'Search products…', greeting: 'Hi! Search by text, image or voice.', topK: 8, }); </script>
Direct API call (no widget)
If you want to build your own search UI, call the API directly from the browser. Note: this exposes your API key to users — use a server-side proxy for production.
async function searchProducts(query) {
const res = await fetch('https://ecomvis.com/api/search/text/', {
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, top_k: 8 }),
});
if (!res.ok) throw new Error(await res.text());
return (await res.json()).results;
}
// Wire up a search input
document.getElementById('search-input')
.addEventListener('input', async e => {
const results = await searchProducts(e.target.value);
renderResults(results); // your own render function
});
Shopify
Add the ecomvis widget to any Shopify store in under two minutes — no app required.
Open the theme editor
Shopify Admin → Online Store → Themes → Edit code.
Edit theme.liquid
Find the closing </body> tag and paste the snippet just above it.
Save & preview
Click Save — the widget launcher appears immediately in the theme preview.
{%- comment -%}ecomvis AI search widget{%- endcomment -%} <script src="https://ecomvis.com/static/js/widget.js" defer></script> <script> document.addEventListener('DOMContentLoaded', function() { EcomvisWidget.init({ apiKey: 'YOUR_API_KEY', position: 'bottom-right', }); }); </script>
mystore.myshopify.com) in Dashboard → Add Website. ecomvis fetches your product feed automatically.WooCommerce (WordPress)
Two methods — a lightweight PHP snippet (recommended) or pasting directly into a child theme.
Method A — functions.php snippet
add_action('wp_footer', 'ecomvis_widget'); function ecomvis_widget() { ?> <script src="https://ecomvis.com/static/js/widget.js" defer></script> <script> document.addEventListener('DOMContentLoaded', function() { EcomvisWidget.init({ apiKey: 'YOUR_API_KEY', position: 'bottom-right', }); }); </script> <?php }
Method B — footer.php
<script src="https://ecomvis.com/static/js/widget.js"></script> <script> EcomvisWidget.init({ apiKey: 'YOUR_API_KEY' }); </script>
Webflow
Open Project Settings → Custom Code
Webflow Dashboard → your project → Settings → Custom Code.
Paste in "Footer Code"
The snippet below goes into the Footer Code box (runs before </body>).
Publish your site
Click Save Changes then re-publish. The widget appears on your live site.
<script src="https://ecomvis.com/static/js/widget.js"></script> <script> EcomvisWidget.init({ apiKey: 'YOUR_API_KEY', position: 'bottom-right', placeholder: 'Search our products…', }); </script>
Wix
Via Wix Velo (Dev Mode)
Enable Dev Mode
Wix Editor → Dev Mode toggle (top menu bar) → Turn on Velo.
Open masterPage.js
In the code panel, select Site → masterPage.js.
Paste the snippet
Wix loads this on every page of your site.
$w.onReady(function () {
const s = document.createElement('script');
s.src = 'https://ecomvis.com/static/js/widget.js';
s.onload = () => EcomvisWidget.init({
apiKey: 'YOUR_API_KEY',
});
document.body.appendChild(s);
});
Custom CMS / Framework
For React, Vue, Next.js, Nuxt, or any custom-built storefront.
import { useEffect } from 'react';
export default function EcomvisWidget() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://ecomvis.com/static/js/widget.js';
script.onload = () => {
window.EcomvisWidget.init({
apiKey: 'YOUR_API_KEY',
position: 'bottom-right',
});
};
document.body.appendChild(script);
return () => { /* cleanup on unmount */ };
}, []);
return null; // widget renders itself into the DOM
}
export default {
install() {
const s = document.createElement('script');
s.src = 'https://ecomvis.com/static/js/widget.js';
s.onload = () => window.EcomvisWidget.init({
apiKey: 'YOUR_API_KEY',
});
document.body.appendChild(s);
},
};
// main.js / nuxt plugin
// app.use(EcomvisPlugin);
interface SearchResult {
name: string;
product_url: string;
score: number;
}
async function ecvSearch(
query: string,
topK = 5,
): Promise<SearchResult[]> {
const res = await fetch('https://ecomvis.com/api/search/text/', {
method: 'POST',
headers: {
'X-API-Key': process.env.ECOMVIS_API_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, top_k: topK }),
});
if (!res.ok) throw new Error(res.statusText);
return (await res.json()).results;
}
Error codes
All errors return a JSON body with an error key describing the issue.
| HTTP status | Meaning | Common cause |
|---|---|---|
| 200 | OK | Request succeeded. Results in results array. |
| 400 | Bad Request | Missing required field, query too short, or invalid file type. |
| 401 | Unauthorised | API key missing from request. |
| 403 | Forbidden | Invalid API key, or store index not yet trained. |
| 429 | Too Many Requests | Daily or monthly quota exceeded for the current plan. |
| 500 | Server Error | Unexpected error — contact info@ecomvis.com. |
{
"error": "API key required. Pass X-API-Key header."
}
Rate limits & quotas
Limits apply per store (per API key). The /api/status/ endpoint returns your current usage.
| Plan | Monthly searches | Concurrent requests |
|---|---|---|
| Free | 50 | 2 |
| Starter Monthly | 5,000 | 2 |
| Starter Yearly | 5,000 | 2 |
| Growth monthly | 15,000 | 2 |
| Growth yearly | 15,000 | 2 |
| Pro monthly | 50,000 | 2 |
| Pro Yearly | 50,000 | 2 |
| Pay As You Go | 9,999,999 | 2 |
When the monthly limit is reached the API returns 429. Upgrade your plan or wait for the next billing cycle to resume.
Widget SDK options
All options passed to EcomvisWidget.init({}):
| Option | Type | Default | Description |
|---|---|---|---|
| apiKeyrequired | string | — | Your store API key. |
| positionoptional | string | "bottom-right" | "bottom-right" or "bottom-left". |
| placeholderoptional | string | "What are you looking for..." | Input placeholder text. |
| greetingoptional | string | "Hi! Search by text, image, or voice." | Opening message shown in the widget. |
| topKoptional | integer | 5 | Number of results to display. |
| primaryColoroptional | string | "#2563eb" | Hex colour for buttons and accents. |
Ready to integrate?
Create a free account, train your index, and go live in minutes.