Beta Feature - The AI Products Extraction API was released in January 2026
and is currently in beta.
Overview
Automatically extract product information from any company’s website including pricing, features, target audience, and more - all powered by AI.
Use Case
The Challenge: Manually researching competitor products, pricing models, and features is time-consuming and inconsistent.
The Solution: Brand.dev’s AI Products API analyzes websites and returns structured product data automatically.
The Result: Build competitive analysis tools, market research dashboards, and lead enrichment systems with up-to-date product information.
Quick Start
import BrandDev from "brand.dev";
const client = new BrandDev({
apiKey: process.env.BRAND_DEV_API_KEY,
});
async function extractProducts(domain: string) {
try {
const response = await client.brand.ai.products({
domain: domain,
maxProducts: 5, // Extract up to 5 products (1-12)
});
return response.products;
} catch (error) {
console.error("Product extraction failed:", error);
return [];
}
}
// Extract products
const products = await extractProducts("stripe.com");
console.log(products);
Response Structure
{
"products": [
{
"name": "<string>",
"description": "<string>",
"features": ["<string>"],
"target_audience": ["<string>"],
"tags": ["<string>"],
"price": {
"amount": 123,
"currency": "<string>",
"billing_frequency": "monthly",
"pricing_model": "per_seat"
},
"url": "<string>",
"category": "<string>",
"image_url": "<string>"
}
]
}
Use Cases
Competitive Analysis Dashboard
async function buildCompetitorAnalysis(competitors: string[]) {
const analysis = await Promise.all(
competitors.map(async (domain) => {
const { brand } = await client.brand.retrieve({ domain });
const response = await client.brand.ai.products({
domain,
maxProducts: 10,
});
return {
company: brand.title,
logo: brand.logos?.[0]?.url,
domain: domain,
products: response.products,
productCount: response.products.length,
pricingModels: [
...new Set(response.products.map((p) => p.price?.pricing_model)),
],
averagePrice: calculateAveragePrice(response.products),
categories: [...new Set(response.products.map((p) => p.category))],
};
}),
);
return analysis;
}
function calculateAveragePrice(products: any[]) {
const prices = products
.filter((p) => p.price?.amount && p.price.billing_frequency === "monthly")
.map((p) => p.price.amount);
if (prices.length === 0) return null;
return prices.reduce((a, b) => a + b, 0) / prices.length;
}
// Usage
const competitors = ["stripe.com", "square.com", "adyen.com"];
const analysis = await buildCompetitorAnalysis(competitors);
interface PricingComparison {
company: string;
logo: string;
products: Array<{
name: string;
price: number;
frequency: string;
model: string;
}>;
}
async function comparePricing(domains: string[]): Promise<PricingComparison[]> {
const comparisons = await Promise.all(
domains.map(async (domain) => {
const { brand } = await client.brand.retrieve({ domain });
const response = await client.brand.ai.products({
domain,
maxProducts: 5,
});
return {
company: brand.title,
logo: brand.logos?.[0]?.url,
products: response.products
.filter((p) => p.price)
.map((p) => ({
name: p.name,
price: p.price.amount,
frequency: p.price.billing_frequency,
model: p.price.pricing_model,
})),
};
}),
);
return comparisons;
}
// Display in UI
const pricing = await comparePricing(["figma.com", "sketch.com", "adobe.com"]);
Market Research
Extract products from an entire industry:
async function researchIndustry(
companies: Array<{ domain: string; name: string }>,
) {
const allProducts = [];
for (const company of companies) {
try {
const response = await client.brand.ai.products({
domain: company.domain,
maxProducts: 10,
});
allProducts.push(
...response.products.map((p) => ({
...p,
company: company.name,
domain: company.domain,
})),
);
} catch (error) {
console.error(`Failed to extract products for ${company.domain}:`, error);
}
// Rate limiting: wait between requests
await new Promise((resolve) => setTimeout(resolve, 1000));
}
// Analyze the market
return {
totalProducts: allProducts.length,
categories: groupBy(allProducts, "category"),
pricingModels: groupBy(allProducts, "price.pricing_model"),
averageFeaturesCount: average(
allProducts.map((p) => p.features?.length || 0),
),
commonFeatures: findCommonFeatures(allProducts),
};
}
function groupBy(items: any[], key: string) {
return items.reduce((acc, item) => {
const value = key.split(".").reduce((obj, k) => obj?.[k], item);
acc[value] = (acc[value] || 0) + 1;
return acc;
}, {});
}
Lead Enrichment
Enrich leads with product information:
async function enrichLeadWithProducts(email: string) {
const domain = email.split("@")[1];
try {
// Get brand data
const { brand } = await client.brand.retrieve({ domain });
// Get products
const response = await client.brand.ai.products({ domain, maxProducts: 5 });
// Enrich lead record
return {
company: brand.title,
logo: brand.logos?.[0]?.url,
industry: brand.industries?.eic?.[0]?.industry,
// Product data
products: response.products.map((p) => p.name),
hasFreemium: response.products.some(
(p) => p.price?.pricing_model === "freemium",
),
hasTrial: response.products.some((p) =>
p.features?.some((f) => f.toLowerCase().includes("trial")),
),
pricingModels: [
...new Set(response.products.map((p) => p.price?.pricing_model)),
],
targetAudience: [
...new Set(response.products.flatMap((p) => p.target_audience || [])),
],
};
} catch (error) {
console.error("Enrichment failed:", error);
return null;
}
}
Understanding Pricing Models
The API returns structured pricing information with these models:
Pricing Model Types
| Model | Description | Example |
|---|
per_seat | Price per user/seat | $10/user/month |
flat | Fixed price | $99 |
tiered | Volume-based tiers | $10 for 0-10, $8 for 11-50 |
usage_based | Pay per use | $0.029 per transaction |
freemium | Free tier + paid | Free + $29/month Pro |
custom | Contact sales | Enterprise pricing |
Billing Frequency
monthly - Billed every month
yearly - Billed annually
one_time - One-time payment
per_transaction - Per usage
usage_based - Based on consumption
Example: Filtering by Pricing Model
const products = await client.brand.ai.products({
domain: "figma.com",
maxProducts: 10,
});
// Find freemium products
const freemiumProducts = products.products.filter(
(p) => p.price?.pricing_model === "freemium",
);
// Find subscription products
const subscriptionProducts = products.products.filter((p) =>
["monthly", "yearly"].includes(p.price?.billing_frequency),
);
// Find usage-based products
const usageBasedProducts = products.products.filter(
(p) => p.price?.pricing_model === "usage_based",
);
Building a Product Database
Store extracted products for analysis:
interface ProductRecord {
id: string;
company_domain: string;
company_name: string;
product_name: string;
price: number | null;
pricing_model: string | null;
features: string[];
extracted_at: Date;
}
async function buildProductDatabase(domains: string[]) {
const products: ProductRecord[] = [];
for (const domain of domains) {
try {
const { brand } = await client.brand.retrieve({ domain });
const response = await client.brand.ai.products({
domain,
maxProducts: 12,
});
for (const product of response.products) {
products.push({
id: `${domain}-${product.name.toLowerCase().replace(/\s+/g, "-")}`,
company_domain: domain,
company_name: brand.title,
product_name: product.name,
price: product.price?.amount || null,
pricing_model: product.price?.pricing_model || null,
features: product.features || [],
extracted_at: new Date(),
});
}
// Store in database
await db.products.insertMany(products);
} catch (error) {
console.error(`Failed for ${domain}:`, error);
}
}
return products;
}
Best Practices
1. Set Appropriate maxProducts
Balance between coverage and cost:
// For quick overview
const response = await client.brand.ai.products({ domain, maxProducts: 3 });
// For comprehensive analysis
const response = await client.brand.ai.products({ domain, maxProducts: 12 });
2. Handle Missing Data
Not all fields are available for all products:
const product = products[0];
const price = product.price?.amount
? `$${product.price.amount}${formatFrequency(product.price.billing_frequency)}`
: "Contact Sales";
const features =
product.features?.length > 0
? product.features
: ["Information not available"];
3. Cache Results
Product data doesn’t change frequently:
const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // 7 days
async function getCachedProducts(domain: string) {
const cached = await redis.get(`products:${domain}`);
if (cached) {
return JSON.parse(cached);
}
const response = await client.brand.ai.products({ domain, maxProducts: 10 });
await redis.setex(
`products:${domain}`,
CACHE_TTL / 1000,
JSON.stringify(response.products),
);
return response.products;
}
4. Process Asynchronously
For large-scale analysis, process in background:
async function scheduleProductExtraction(domains: string[]) {
for (const domain of domains) {
await queue.add("extract-products", {
domain,
maxProducts: 10,
});
}
}
// Worker process
queue.process("extract-products", async (job) => {
const { domain, maxProducts } = job.data;
const response = await client.brand.ai.products({ domain, maxProducts });
await db.products.upsert({
domain,
products: response.products,
extracted_at: new Date(),
});
});
Limitations
Beta Limitations: - Maximum 12 products per request - Works best with SaaS
and B2B companies - Accuracy varies by website structure - Some pricing may
not be detected (enterprise/custom pricing)
Use Case Examples
1. Competitor Monitoring
Track competitor product launches and pricing changes
2. Market Research
Analyze product offerings across an entire industry
3. Sales Enablement
Equip sales teams with competitive intelligence
4. Lead Scoring
Score leads based on their product offerings
5. Partnership Discovery
Find complementary products for partnerships
Have feedback on the AI Products API? This is a beta feature and we’d love
to hear your thoughts. Contact us with feedback or
feature requests.