curl --request POST \
--url https://search.glood.ai/api/storefront/v1/headless/image-search \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-shop: <x-shop>' \
--data '
{
"image": "<string>",
"image_url": "<string>",
"facets": {},
"locale": "en",
"market": 123,
"publication_ids": [
"30085840999"
],
"view": "product_details",
"pagination": {
"page": 1,
"limit": 20
},
"visitor_id": "<string>",
"client_id": "<string>",
"customer_id": "<string>"
}
'import requests
url = "https://search.glood.ai/api/storefront/v1/headless/image-search"
payload = {
"image": "<string>",
"image_url": "<string>",
"facets": {},
"locale": "en",
"market": 123,
"publication_ids": ["30085840999"],
"view": "product_details",
"pagination": {
"page": 1,
"limit": 20
},
"visitor_id": "<string>",
"client_id": "<string>",
"customer_id": "<string>"
}
headers = {
"x-shop": "<x-shop>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-shop': '<x-shop>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
image: '<string>',
image_url: '<string>',
facets: {},
locale: 'en',
market: 123,
publication_ids: ['30085840999'],
view: 'product_details',
pagination: {page: 1, limit: 20},
visitor_id: '<string>',
client_id: '<string>',
customer_id: '<string>'
})
};
fetch('https://search.glood.ai/api/storefront/v1/headless/image-search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://search.glood.ai/api/storefront/v1/headless/image-search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'image' => '<string>',
'image_url' => '<string>',
'facets' => [
],
'locale' => 'en',
'market' => 123,
'publication_ids' => [
'30085840999'
],
'view' => 'product_details',
'pagination' => [
'page' => 1,
'limit' => 20
],
'visitor_id' => '<string>',
'client_id' => '<string>',
'customer_id' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-shop: <x-shop>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://search.glood.ai/api/storefront/v1/headless/image-search"
payload := strings.NewReader("{\n \"image\": \"<string>\",\n \"image_url\": \"<string>\",\n \"facets\": {},\n \"locale\": \"en\",\n \"market\": 123,\n \"publication_ids\": [\n \"30085840999\"\n ],\n \"view\": \"product_details\",\n \"pagination\": {\n \"page\": 1,\n \"limit\": 20\n },\n \"visitor_id\": \"<string>\",\n \"client_id\": \"<string>\",\n \"customer_id\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-shop", "<x-shop>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://search.glood.ai/api/storefront/v1/headless/image-search")
.header("x-shop", "<x-shop>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"image\": \"<string>\",\n \"image_url\": \"<string>\",\n \"facets\": {},\n \"locale\": \"en\",\n \"market\": 123,\n \"publication_ids\": [\n \"30085840999\"\n ],\n \"view\": \"product_details\",\n \"pagination\": {\n \"page\": 1,\n \"limit\": 20\n },\n \"visitor_id\": \"<string>\",\n \"client_id\": \"<string>\",\n \"customer_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://search.glood.ai/api/storefront/v1/headless/image-search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-shop"] = '<x-shop>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image\": \"<string>\",\n \"image_url\": \"<string>\",\n \"facets\": {},\n \"locale\": \"en\",\n \"market\": 123,\n \"publication_ids\": [\n \"30085840999\"\n ],\n \"view\": \"product_details\",\n \"pagination\": {\n \"page\": 1,\n \"limit\": 20\n },\n \"visitor_id\": \"<string>\",\n \"client_id\": \"<string>\",\n \"customer_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"products": [
{
"product_id": 9311227838783,
"title": "Running Shoe",
"handle": "running-shoe",
"product_type": "Shoes",
"vendor": "Acme",
"tags": ["sale", "summer"],
"price": 49.99,
"compare_at_price": 69.99,
"display_price": 49.99,
"display_compare_at_price": 69.99,
"display_currency": "USD",
"original_currency": "USD",
"currency_rate": 1,
"available_for_sale": true,
"is_in_stock": true,
"total_inventory": 42,
"image": { "id": "gid://shopify/ProductImage/1", "url": "https://cdn.shopify.com/s/files/1/shoe.jpg", "width": 800, "height": 800, "alt_text": "Running Shoe" },
"featured_media": null,
"media": [],
"options": [ { "id": 111, "name": "Size", "position": 1, "values": ["S", "M", "L"] } ],
"variants": [],
"metafields": []
}
],
"pagination": {
"total": 60, "page": 1, "limit": 20, "total_pages": 3,
"has_next_page": true, "has_prev_page": false
},
"search_metadata": {
"processing_time": 340,
"search_type": "image_vector",
"image_analysis": null,
"image_caption": "a red running shoe",
"search_text": "red running shoe",
"has_embedding": true,
"errors": [],
"dominant_colors": ["#ff0000"]
}
}
{
"error": "Image must be one of jpeg, png, webp"
}
Image Search
Visual (image) search. Accepts a multipart file OR a JSON base64 image / data: URL / http(s) image URL (exactly one source). Images are strictly validated before search. Auth: Authorization: Bearer <gl_sf_...> + x-shop.
curl --request POST \
--url https://search.glood.ai/api/storefront/v1/headless/image-search \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-shop: <x-shop>' \
--data '
{
"image": "<string>",
"image_url": "<string>",
"facets": {},
"locale": "en",
"market": 123,
"publication_ids": [
"30085840999"
],
"view": "product_details",
"pagination": {
"page": 1,
"limit": 20
},
"visitor_id": "<string>",
"client_id": "<string>",
"customer_id": "<string>"
}
'import requests
url = "https://search.glood.ai/api/storefront/v1/headless/image-search"
payload = {
"image": "<string>",
"image_url": "<string>",
"facets": {},
"locale": "en",
"market": 123,
"publication_ids": ["30085840999"],
"view": "product_details",
"pagination": {
"page": 1,
"limit": 20
},
"visitor_id": "<string>",
"client_id": "<string>",
"customer_id": "<string>"
}
headers = {
"x-shop": "<x-shop>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-shop': '<x-shop>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
image: '<string>',
image_url: '<string>',
facets: {},
locale: 'en',
market: 123,
publication_ids: ['30085840999'],
view: 'product_details',
pagination: {page: 1, limit: 20},
visitor_id: '<string>',
client_id: '<string>',
customer_id: '<string>'
})
};
fetch('https://search.glood.ai/api/storefront/v1/headless/image-search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://search.glood.ai/api/storefront/v1/headless/image-search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'image' => '<string>',
'image_url' => '<string>',
'facets' => [
],
'locale' => 'en',
'market' => 123,
'publication_ids' => [
'30085840999'
],
'view' => 'product_details',
'pagination' => [
'page' => 1,
'limit' => 20
],
'visitor_id' => '<string>',
'client_id' => '<string>',
'customer_id' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-shop: <x-shop>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://search.glood.ai/api/storefront/v1/headless/image-search"
payload := strings.NewReader("{\n \"image\": \"<string>\",\n \"image_url\": \"<string>\",\n \"facets\": {},\n \"locale\": \"en\",\n \"market\": 123,\n \"publication_ids\": [\n \"30085840999\"\n ],\n \"view\": \"product_details\",\n \"pagination\": {\n \"page\": 1,\n \"limit\": 20\n },\n \"visitor_id\": \"<string>\",\n \"client_id\": \"<string>\",\n \"customer_id\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-shop", "<x-shop>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://search.glood.ai/api/storefront/v1/headless/image-search")
.header("x-shop", "<x-shop>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"image\": \"<string>\",\n \"image_url\": \"<string>\",\n \"facets\": {},\n \"locale\": \"en\",\n \"market\": 123,\n \"publication_ids\": [\n \"30085840999\"\n ],\n \"view\": \"product_details\",\n \"pagination\": {\n \"page\": 1,\n \"limit\": 20\n },\n \"visitor_id\": \"<string>\",\n \"client_id\": \"<string>\",\n \"customer_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://search.glood.ai/api/storefront/v1/headless/image-search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-shop"] = '<x-shop>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image\": \"<string>\",\n \"image_url\": \"<string>\",\n \"facets\": {},\n \"locale\": \"en\",\n \"market\": 123,\n \"publication_ids\": [\n \"30085840999\"\n ],\n \"view\": \"product_details\",\n \"pagination\": {\n \"page\": 1,\n \"limit\": 20\n },\n \"visitor_id\": \"<string>\",\n \"client_id\": \"<string>\",\n \"customer_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"products": [
{
"product_id": 9311227838783,
"title": "Running Shoe",
"handle": "running-shoe",
"product_type": "Shoes",
"vendor": "Acme",
"tags": ["sale", "summer"],
"price": 49.99,
"compare_at_price": 69.99,
"display_price": 49.99,
"display_compare_at_price": 69.99,
"display_currency": "USD",
"original_currency": "USD",
"currency_rate": 1,
"available_for_sale": true,
"is_in_stock": true,
"total_inventory": 42,
"image": { "id": "gid://shopify/ProductImage/1", "url": "https://cdn.shopify.com/s/files/1/shoe.jpg", "width": 800, "height": 800, "alt_text": "Running Shoe" },
"featured_media": null,
"media": [],
"options": [ { "id": 111, "name": "Size", "position": 1, "values": ["S", "M", "L"] } ],
"variants": [],
"metafields": []
}
],
"pagination": {
"total": 60, "page": 1, "limit": 20, "total_pages": 3,
"has_next_page": true, "has_prev_page": false
},
"search_metadata": {
"processing_time": 340,
"search_type": "image_vector",
"image_analysis": null,
"image_caption": "a red running shoe",
"search_text": "red running shoe",
"has_embedding": true,
"errors": [],
"dominant_colors": ["#ff0000"]
}
}
{
"error": "Image must be one of jpeg, png, webp"
}
{
"status": "ok",
"products": [
{
"product_id": 9311227838783,
"title": "Running Shoe",
"handle": "running-shoe",
"product_type": "Shoes",
"vendor": "Acme",
"tags": ["sale", "summer"],
"price": 49.99,
"compare_at_price": 69.99,
"display_price": 49.99,
"display_compare_at_price": 69.99,
"display_currency": "USD",
"original_currency": "USD",
"currency_rate": 1,
"available_for_sale": true,
"is_in_stock": true,
"total_inventory": 42,
"image": { "id": "gid://shopify/ProductImage/1", "url": "https://cdn.shopify.com/s/files/1/shoe.jpg", "width": 800, "height": 800, "alt_text": "Running Shoe" },
"featured_media": null,
"media": [],
"options": [ { "id": 111, "name": "Size", "position": 1, "values": ["S", "M", "L"] } ],
"variants": [],
"metafields": []
}
],
"pagination": {
"total": 60, "page": 1, "limit": 20, "total_pages": 3,
"has_next_page": true, "has_prev_page": false
},
"search_metadata": {
"processing_time": 340,
"search_type": "image_vector",
"image_analysis": null,
"image_caption": "a red running shoe",
"search_text": "red running shoe",
"has_embedding": true,
"errors": [],
"dominant_colors": ["#ff0000"]
}
}
{
"error": "Image must be one of jpeg, png, webp"
}
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Shopify store URL. Resolves the shop for the request (headless does not accept ?shop=).
"shop.myshopify.com"
Body
Request body
Visual (image) search. Accepts a multipart file, a base64 image, a data: URL, or an http(s) image URL. Images are strictly validated (jpeg/png/webp, 1KB-5MB, 100x100 to 4096x4096) before search.
Raw base64 OR a data: URL. Exactly one of image / image_url is required. (Also accepted as a multipart image file upload.)
An http(s) image URL (fetched server-side, SSRF-guarded) OR a data: base64 URL. Exactly one of image / image_url is required.
Applied filters (object or array form).
- object
- object[]
BCP-47 locale.
Shopify market id.
Optional. Numeric Shopify publication (sales channel) ids. When present, only products published on at least one of these channels are returned and the default "published to the Online Store" gate is replaced by this filter; market and B2B filters still apply. A single id may be sent without the array wrapper. Each id must be one the merchant enabled under Settings → Sales channels; unknown ids return 400. The id is the numeric tail of gid://shopify/Publication/.
50^[0-9]+$["30085840999"]
Product render mode.
product_details, product_ids Page-based pagination.
Show child attributes
Show child attributes
Anonymous device/browser UID (the gl_s_uid cookie). The primary personalization key; stays stable when a customer logs in.
Per-session / per-device identifier.
Shopify customer id. Present only when the shopper is logged in; enables customer-level personalization.
Response
Image search results
Visual search results with pagination and image-analysis metadata.
Was this page helpful?