Shopify App Detector API
Professional API for detecting Shopify apps, themes, and store technologies with enterprise-grade reliability
Overview
The ShopScan Detector API analyzes any website to detect installed Shopify apps, themes, store metadata, and technologies. Built for developers, researchers, and businesses who need reliable e-commerce intelligence.
https://scan.shopscan.app/api/v1
Key Features
- Detect Shopify apps and themes from any store URL
- Full store metadata including title, description, currency, and domain
- Detailed theme data with pricing, author, and screenshots
- App categorization with subcategories, ratings, and developer info
- Headless store detection
- Real-time server-side scanning with 99.9% uptime
Pricing Plans
Choose a plan that fits your needs. All plans include full API access with theme data, app detection, and store metadata.
Starter
- 10,000 requests/month
- 3 requests/second
- Full app & theme detection
- Store metadata
- Email support
Growth
- 50,000 requests/month
- 5 requests/second
- Full app & theme detection
- Store metadata
- Priority support
Pro
- 250,000 requests/month
- 10 requests/second
- Full app & theme detection
- Store metadata
- Priority support
Business
- 1,000,000 requests/month
- 20 requests/second
- Full app & theme detection
- Store metadata
- Dedicated support
Authentication
All API requests require a valid API key passed as a query parameter. You'll receive your API key after subscribing to a plan.
| Parameter | Type | Required | Description |
|---|---|---|---|
api_key |
string | Required | Your unique API authentication key |
API Endpoints
GET /api/v1/scan
Scan a website and detect Shopify apps, theme, store metadata, and technologies.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Required | Domain or URL to scan (e.g., devluxx.com or colourpop.com) |
api_key |
string | Required | Your API authentication key |
Example Request
curl "https://scan.shopscan.app/api/v1/scan?url=devluxx.com&api_key=YOUR_API_KEY"Response Examples
Shopify Store Response
Successful scan of a Shopify store
{
"url": "https://devluxx.com",
"is_shopify": true,
"is_headless": false,
"store_meta": {
"name": "DevLuxx.com",
"country": "BD",
"currency": "USD",
"domain": "www.devluxx.com",
"myshopify_domain": "sakinur5.myshopify.com",
"published_products_count": 28
},
"store_title": "Shopify Web Development Agency – DevLuxx.com",
"meta_description": "Devluxx.com delivers top-notch web development services...",
"theme": "Dawn",
"theme_data": {
"theme_name": "Dawn",
"theme_url": "https://themes.shopify.com/themes/dawn",
"theme_pricing_type": "free",
"theme_author": "Shopify",
"total_reviewers": 267
},
"detected_apps": [
{
"app_handle": "klaviyo-email-marketing",
"name": "Klaviyo: Email Marketing & SMS",
"app_logo": "https://cdn.shopscan.app/.../klaviyo-email-marketing.png",
"rating": 4.6,
"review_count": 2568,
"developer_name": "Klaviyo",
"pricing_type": "freemium",
"has_free_plan": true,
"is_recommended": false,
"app_categories": [
{ "category": "Marketing and Conversion", "subcategories": ["Email Marketing", "SMS Marketing"] }
]
}
],
"total_detected": 8
}Non-Shopify Store Response
Website is not a Shopify store
{
"url": "https://example.com",
"is_shopify": false
}Response Fields
| Field | Type | Description |
|---|---|---|
url |
string | The scanned URL |
is_shopify |
boolean | true if the store runs on Shopify |
is_headless |
boolean | true if the store uses a headless frontend |
store_meta |
object | Store metadata: name, city, country, currency, domain, myshopify_domain, product/collection counts |
store_title |
string | HTML page title of the store |
meta_description |
string | Meta description of the store |
theme |
string | Name of the detected Shopify theme |
theme_data |
object|null | Theme details: name, URL, screenshot, pricing, author, feedback percentage, reviewer count |
detected_apps |
array | List of detected apps with handle, name, logo, rating, reviews, developer, pricing, categories |
total_detected |
integer | Total number of detected apps |
Detected App Fields
| Field | Type | Description |
|---|---|---|
app_handle |
string | Unique app identifier (slug) |
name |
string | App display name |
app_logo |
string | URL of the app logo image |
app_url |
string | App store listing URL |
short_description |
string | Brief description of the app |
rating |
number | Average rating (1-5) |
review_count |
integer | Total number of reviews |
developer_name |
string | Name of the app developer |
pricing_type |
string | free, freemium, or paid |
has_free_plan |
boolean | Whether the app offers a free plan |
has_free_trial |
boolean | Whether the app offers a free trial |
is_recommended |
boolean | Whether the app is editorially recommended |
is_featured |
boolean | Whether the app is featured |
category |
string | Primary category type (app) |
app_categories |
array | Detailed categories and subcategories |
Code Examples
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://scan.shopscan.app/api/v1/scan";
async function scanStore(url) {
const response = await fetch(
`${BASE_URL}?url=${encodeURIComponent(url)}&api_key=${API_KEY}`
);
if (response.status === 429) {
console.error("Rate limited. Retry after 1 second.");
return null;
}
if (!response.ok) {
const err = await response.json();
console.error("Error:", err.error);
return null;
}
return await response.json();
}
const data = await scanStore("devluxx.com");
if (data && data.is_shopify) {
console.log("Theme:", data.theme);
console.log("Theme Author:", data.theme_data?.theme_author);
console.log("Store:", data.store_meta?.name);
console.log("Apps found:", data.total_detected);
data.detected_apps.forEach(app => {
console.log(`- ${app.name} (${app.rating}/5, ${app.review_count} reviews)`);
});
} else if (data) {
console.log("Not a Shopify store");
}import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://scan.shopscan.app/api/v1/scan"
def scan_store(url, retries=2):
params = {"url": url, "api_key": API_KEY}
response = requests.get(BASE_URL, params=params)
if response.status_code == 429:
if retries > 0:
time.sleep(1)
return scan_store(url, retries - 1)
print("Rate limited. Try again later.")
return None
if response.status_code != 200:
print(f"Error {response.status_code}: {response.json().get('error')}")
return None
return response.json()
data = scan_store("devluxx.com")
if data and data["is_shopify"]:
print(f"Theme: {data['theme']}")
print(f"Theme Author: {data['theme_data']['theme_author']}")
print(f"Store: {data['store_meta']['name']}")
print(f"Apps found: {data['total_detected']}")
for app in data["detected_apps"]:
print(f"- {app['name']} ({app['rating']}/5, {app['review_count']} reviews)")
elif data:
print("Not a Shopify store")$apiKey = "YOUR_API_KEY";
$baseUrl = "https://scan.shopscan.app/api/v1/scan";
function scanStore($url) {
global $apiKey, $baseUrl;
$queryUrl = $baseUrl . "?" . http_build_query([
"url" => $url,
"api_key" => $apiKey
]);
$ch = curl_init($queryUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 429) {
echo "Rate limited. Retry after 1 second.\n";
return null;
}
if ($httpCode !== 200) {
$err = json_decode($response, true);
echo "Error: " . ($err['error'] ?? 'Unknown') . "\n";
return null;
}
return json_decode($response, true);
}
$data = scanStore("devluxx.com");
if ($data && $data['is_shopify']) {
echo "Theme: " . $data['theme'] . "\n";
echo "Theme Author: " . $data['theme_data']['theme_author'] . "\n";
echo "Store: " . $data['store_meta']['name'] . "\n";
echo "Apps found: " . $data['total_detected'] . "\n";
foreach ($data['detected_apps'] as $app) {
echo "- {$app['name']} ({$app['rating']}/5, {$app['review_count']} reviews)\n";
}
} elseif ($data) {
echo "Not a Shopify store\n";
}# Scan a Shopify store
curl "https://scan.shopscan.app/api/v1/scan?url=devluxx.com&api_key=YOUR_API_KEY"
# Scan by full URL
curl "https://scan.shopscan.app/api/v1/scan?url=colourpop.com&api_key=YOUR_API_KEY"
# Check if a site is Shopify
curl "https://scan.shopscan.app/api/v1/scan?url=example.com&api_key=YOUR_API_KEY"Error Handling
Error Responses
Missing required parameter
{
"error": "Missing required parameter: url"
}Invalid or missing API key
{
"error": "Invalid API key"
}Account inactive or subscription expired
{
"error": "Account inactive or subscription expired"
}Too many requests per second
{
"error": "Rate limit exceeded. Max 3 requests per second.",
"retry_after": 1
}Monthly request quota exceeded
{
"error": "Monthly request limit exceeded. Please upgrade your plan.",
"limit": 10000,
"used": 10000
}Internal server error or scan failure
{
"error": "Scan failed. The website may be unreachable or blocking requests."
}HTTP Status Codes
| Code | Description |
|---|---|
| 200 | Success (both Shopify and non-Shopify responses) |
| 400 | Bad Request (missing url parameter) |
| 401 | Unauthorized (invalid or missing API key) |
| 403 | Forbidden (account disabled or subscription expired) |
| 429 | Rate Limited (per-second or monthly limit exceeded) |
| 500 | Internal Server Error (scan failed or server issue) |
Rate Limits
Rate limits are enforced per API key. Both per-second and monthly limits apply based on your plan.
| Plan | Monthly Requests | Requests/Second | Price |
|---|---|---|---|
| Starter | 10,000 | 3 | $19/mo |
| Growth | 50,000 | 5 | $49/mo |
| Pro | 250,000 | 10 | $99/mo |
| Business | 1,000,000 | 20 | $249/mo |
- Implement retry logic with a 1-second delay for
429responses - Cache scan results to minimize API calls for frequently checked stores
- Set a request timeout of 60 seconds for each scan
- Handle
theme_databeingnullfor unrecognized themes - Check
is_shopifybefore accessing Shopify-specific fields - Monitor your monthly usage via the customer portal