TikTok Shop Product Research: Find Winning Products Using Data
You see someone making $50K per month on TikTok Shop. You think "I can do that." You pick a product that looks cool. You order inventory. You create content.
Nobody buys.
What went wrong? You picked based on gut feeling instead of data. The product might be trendy, but the data shows demand is already declining. Or competition is too high. Or the price point is wrong.
I wasted $4,000 on inventory for a product that looked perfect. Spent weeks creating content. Made 3 sales total. The data was right there—I just did not look at it.
Now I research products with data before buying any inventory. I find products with proven demand, manageable competition, and clear profit margins. I know if a product will work before I spend a dollar on it.
Let me show you how to find winning TikTok Shop products using data analysis.
Why Most Products Fail
Most people pick products randomly or copy what they see going viral. But by the time you see it going viral, you are already too late.
The Product Lifecycle on TikTok
Every product follows a pattern:
Stage 1: Discovery (Week 1-2)
- Few sellers testing the product
- Low competition
- Early adopters buying
- Best time to enter
Stage 2: Growth (Week 3-6)
- Product gaining traction
- More sellers joining
- Sales accelerating
- Still good time to enter
Stage 3: Saturation (Week 7-10)
- Everyone selling it
- High competition
- Price wars starting
- Margins getting squeezed
Stage 4: Decline (Week 11+)
- Oversaturated market
- Buyers tired of seeing it
- Low profit margins
- Time to move to next product
You want to enter during Discovery or early Growth. Not after everyone else is already selling it.
Find Products in the Discovery Phase
Look for products before they explode.
Method 1: Monitor Hashtag Growth
Track product-related hashtags:
const axios = require('axios');
async function findEmergingProducts(productHashtags) {
console.log('\n=== EMERGING PRODUCT ANALYSIS ===\n');
const results = [];
for (const hashtag of productHashtags) {
try {
const response = await axios.get(
'https://api.sociavault.com/tiktok/hashtag',
{
params: {
hashtag: hashtag,
amount: 100
},
headers: {
'X-API-Key': process.env.SOCIAVAULT_API_KEY
}
}
);
const videos = response.data.videos;
// Analyze time distribution
const now = Date.now() / 1000;
const last7days = videos.filter(v => v.createTime > now - (7 * 24 * 60 * 60));
const previous7days = videos.filter(v =>
v.createTime > now - (14 * 24 * 60 * 60) &&
v.createTime <= now - (7 * 24 * 60 * 60)
);
const recentCount = last7days.length;
const previousCount = previous7days.length;
const growthRate = previousCount > 0
? ((recentCount - previousCount) / previousCount * 100).toFixed(1)
: 'N/A';
// Calculate average engagement
let totalViews = 0;
let totalEngagement = 0;
last7days.forEach(video => {
totalViews += video.playCount;
totalEngagement += video.diggCount + video.commentCount + video.shareCount;
});
const avgViews = recentCount > 0 ? Math.round(totalViews / recentCount) : 0;
const avgEngagement = recentCount > 0 ? Math.round(totalEngagement / recentCount) : 0;
const engagementRate = avgViews > 0 ? ((avgEngagement / avgViews) * 100).toFixed(2) : '0';
results.push({
hashtag,
recentPosts: recentCount,
growthRate: growthRate === 'N/A' ? 0 : parseFloat(growthRate),
avgViews,
avgEngagement,
engagementRate: parseFloat(engagementRate)
});
} catch (error) {
console.error(`Failed to analyze #${hashtag}:`, error.message);
}
}
// Sort by potential (high growth, low volume = emerging)
results.sort((a, b) => {
// Prioritize: moderate volume with high growth
const scoreA = (a.growthRate / 10) + (a.recentPosts < 50 ? 20 : 0);
const scoreB = (b.growthRate / 10) + (b.recentPosts < 50 ? 20 : 0);
return scoreB - scoreA;
});
console.log('Emerging Products (sorted by opportunity):\n');
results.forEach((result, i) => {
console.log(`${i + 1}. #${result.hashtag}`);
console.log(` Posts (last 7 days): ${result.recentPosts}`);
console.log(` Growth Rate: ${result.growthRate}%`);
console.log(` Avg Views: ${result.avgViews.toLocaleString()}`);
console.log(` Engagement Rate: ${result.engagementRate}%`);
// Determine opportunity
if (result.recentPosts < 50 && result.growthRate > 50) {
console.log(` 🌟 OPPORTUNITY: Low competition, high growth`);
} else if (result.recentPosts < 100 && result.growthRate > 30) {
console.log(` ✅ GOOD: Moderate competition, growing`);
} else if (result.recentPosts > 200) {
console.log(` ⚠️ SATURATED: High competition`);
}
console.log('');
});
return results;
}
// Test potential product hashtags
const productHashtags = [
'portablefan',
'neckfan',
'coolinggadget',
'summertech',
'travelgadget'
];
const emergingProducts = await findEmergingProducts(productHashtags);
Method 2: Analyze Top-Selling Products
Find what is actually selling well:
async function analyzeProductPerformance(productKeyword) {
try {
const response = await axios.get(
'https://api.sociavault.com/tiktok/keyword-search',
{
params: {
keyword: productKeyword,
amount: 50
},
headers: {
'X-API-Key': process.env.SOCIAVAULT_API_KEY
}
}
);
const videos = response.data.videos;
console.log(`\n=== PRODUCT PERFORMANCE: ${productKeyword} ===\n`);
// Sort by engagement
const sortedByEngagement = videos.sort((a, b) => {
const engageA = a.diggCount + a.commentCount + a.shareCount;
const engageB = b.diggCount + b.commentCount + b.shareCount;
return engageB - engageA;
});
const topPerformers = sortedByEngagement.slice(0, 10);
// Analyze patterns in top performers
const patterns = {
avgViews: 0,
avgLikes: 0,
avgComments: 0,
avgShares: 0,
totalVideos: topPerformers.length,
creators: new Set(),
commonWords: new Map()
};
topPerformers.forEach(video => {
patterns.avgViews += video.playCount;
patterns.avgLikes += video.diggCount;
patterns.avgComments += video.commentCount;
patterns.avgShares += video.shareCount;
patterns.creators.add(video.author.uniqueId);
// Extract common description words
const desc = (video.description || '').toLowerCase();
const words = desc.match(/\b\w{4,}\b/g) || [];
words.forEach(word => {
patterns.commonWords.set(word, (patterns.commonWords.get(word) || 0) + 1);
});
});
patterns.avgViews = Math.round(patterns.avgViews / patterns.totalVideos);
patterns.avgLikes = Math.round(patterns.avgLikes / patterns.totalVideos);
patterns.avgComments = Math.round(patterns.avgComments / patterns.totalVideos);
patterns.avgShares = Math.round(patterns.avgShares / patterns.totalVideos);
console.log('Top 10 Performing Videos:');
console.log(`Avg Views: ${patterns.avgViews.toLocaleString()}`);
console.log(`Avg Likes: ${patterns.avgLikes.toLocaleString()}`);
console.log(`Avg Comments: ${patterns.avgComments.toLocaleString()}`);
console.log(`Avg Shares: ${patterns.avgShares.toLocaleString()}`);
console.log(`Unique Creators: ${patterns.creators.size}`);
// Show most common words (likely selling points)
const topWords = Array.from(patterns.commonWords.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
console.log('\nMost Common Words (likely key selling points):');
topWords.forEach(([word, count]) => {
console.log(`- ${word}: ${count} mentions`);
});
// Sample top videos
console.log('\nTop 3 Videos:');
topPerformers.slice(0, 3).forEach((video, i) => {
console.log(`\n${i + 1}. @${video.author.uniqueId}`);
console.log(` Views: ${video.playCount.toLocaleString()}`);
console.log(` Engagement: ${(video.diggCount + video.commentCount + video.shareCount).toLocaleString()}`);
console.log(` Description: ${(video.description || '').substring(0, 80)}...`);
});
return patterns;
} catch (error) {
console.error('Failed to analyze product:', error.message);
return null;
}
}
const productAnalysis = await analyzeProductPerformance('portable blender');
Method 3: Competition Analysis
Check how many sellers and their performance:
async function analyzeCompetition(productKeyword) {
try {
const response = await axios.get(
'https://api.sociavault.com/tiktok/keyword-search',
{
params: {
keyword: productKeyword,
amount: 100
},
headers: {
'X-API-Key': process.env.SOCIAVAULT_API_KEY
}
}
);
const videos = response.data.videos;
console.log(`\n=== COMPETITION ANALYSIS: ${productKeyword} ===\n`);
// Group by creator
const creatorStats = new Map();
videos.forEach(video => {
const creator = video.author.uniqueId;
if (!creatorStats.has(creator)) {
creatorStats.set(creator, {
videos: 0,
totalViews: 0,
totalEngagement: 0,
avgViews: 0,
followers: video.author.followerCount || 0
});
}
const stats = creatorStats.get(creator);
stats.videos++;
stats.totalViews += video.playCount;
stats.totalEngagement += video.diggCount + video.commentCount + video.shareCount;
});
// Calculate averages
creatorStats.forEach((stats, creator) => {
stats.avgViews = Math.round(stats.totalViews / stats.videos);
stats.avgEngagement = Math.round(stats.totalEngagement / stats.videos);
});
// Sort by total engagement
const topCompetitors = Array.from(creatorStats.entries())
.sort((a, b) => b[1].totalEngagement - a[1].totalEngagement)
.slice(0, 10);
console.log(`Total Competing Creators: ${creatorStats.size}`);
console.log(`Total Videos: ${videos.length}\n`);
console.log('Top 10 Competitors:');
topCompetitors.forEach(([creator, stats], i) => {
console.log(`\n${i + 1}. @${creator}`);
console.log(` Videos: ${stats.videos}`);
console.log(` Followers: ${stats.followers.toLocaleString()}`);
console.log(` Avg Views: ${stats.avgViews.toLocaleString()}`);
console.log(` Avg Engagement: ${stats.avgEngagement.toLocaleString()}`);
});
// Analyze competition level
let competitionLevel;
if (creatorStats.size < 20) {
competitionLevel = '🟢 LOW - Great opportunity';
} else if (creatorStats.size < 50) {
competitionLevel = '🟡 MODERATE - Still good';
} else if (creatorStats.size < 100) {
competitionLevel = '🟠 HIGH - Challenging';
} else {
competitionLevel = '🔴 VERY HIGH - Saturated';
}
console.log(`\nCompetition Level: ${competitionLevel}`);
return {
totalCreators: creatorStats.size,
totalVideos: videos.length,
topCompetitors: topCompetitors.map(([creator, stats]) => ({
creator,
...stats
})),
competitionLevel
};
} catch (error) {
console.error('Failed to analyze competition:', error.message);
return null;
}
}
const competitionData = await analyzeCompetition('portable blender');
Calculate Profit Potential
Estimate if the product is worth selling:
function calculateProfitPotential(productData) {
console.log('\n=== PROFIT POTENTIAL CALCULATOR ===\n');
// Input your numbers
const costs = {
productCost: 8.50, // Cost per unit from supplier
shipping: 3.00, // Shipping to customer
tiktokFee: 0, // TikTok Shop fee (percentage, calculated below)
adSpend: 100, // Monthly ad spend (optional)
unitsPerMonth: 200 // Expected sales
};
const pricing = {
retailPrice: 29.99 // What you charge customers
};
// Calculate fees
const tiktokFeePercent = 0.08; // TikTok Shop takes 8%
const tiktokFeeAmount = pricing.retailPrice * tiktokFeePercent;
// Calculate per-unit profit
const costPerUnit = costs.productCost + costs.shipping + tiktokFeeAmount;
const profitPerUnit = pricing.retailPrice - costPerUnit;
const profitMargin = ((profitPerUnit / pricing.retailPrice) * 100).toFixed(1);
// Calculate monthly profit
const monthlyRevenue = pricing.retailPrice * costs.unitsPerMonth;
const monthlyCosts = costPerUnit * costs.unitsPerMonth + costs.adSpend;
const monthlyProfit = monthlyRevenue - monthlyCosts;
const monthlyMargin = ((monthlyProfit / monthlyRevenue) * 100).toFixed(1);
console.log('Per Unit Economics:');
console.log(`Retail Price: $${pricing.retailPrice}`);
console.log(`Product Cost: $${costs.productCost}`);
console.log(`Shipping: $${costs.shipping}`);
console.log(`TikTok Fee (8%): $${tiktokFeeAmount.toFixed(2)}`);
console.log(`Total Cost: $${costPerUnit.toFixed(2)}`);
console.log(`Profit per Unit: $${profitPerUnit.toFixed(2)}`);
console.log(`Profit Margin: ${profitMargin}%\n`);
console.log('Monthly Projections:');
console.log(`Expected Sales: ${costs.unitsPerMonth} units`);
console.log(`Revenue: $${monthlyRevenue.toFixed(2)}`);
console.log(`Costs: $${monthlyCosts.toFixed(2)}`);
console.log(`Net Profit: $${monthlyProfit.toFixed(2)}`);
console.log(`Profit Margin: ${monthlyMargin}%\n`);
// Recommendation
let recommendation;
if (profitPerUnit < 5) {
recommendation = '❌ NOT VIABLE - Profit too low';
} else if (profitPerUnit < 10) {
recommendation = '⚠️ RISKY - Thin margins';
} else if (profitPerUnit < 15) {
recommendation = '✅ GOOD - Decent profit margins';
} else {
recommendation = '🌟 EXCELLENT - High profit potential';
}
console.log(`Recommendation: ${recommendation}`);
return {
profitPerUnit,
profitMargin: parseFloat(profitMargin),
monthlyProfit,
recommendation
};
}
const profitAnalysis = calculateProfitPotential({
productCost: 8.50,
retailPrice: 29.99
});
The Complete Product Research System
Put it all together:
class ProductResearcher {
constructor() {
this.products = [];
}
async researchProduct(keyword) {
console.log(`\n${'='.repeat(60)}`);
console.log(`COMPLETE PRODUCT RESEARCH: ${keyword}`);
console.log(`${'='.repeat(60)}`);
const research = {
keyword,
timestamp: Date.now(),
scores: {},
recommendation: ''
};
try {
// Step 1: Check market demand
console.log('\nStep 1: Analyzing Market Demand...');
const demandAnalysis = await analyzeProductPerformance(keyword);
research.scores.demand = this.scoreDemand(demandAnalysis);
// Step 2: Check competition
console.log('\nStep 2: Analyzing Competition...');
const competitionAnalysis = await analyzeCompetition(keyword);
research.scores.competition = this.scoreCompetition(competitionAnalysis);
// Step 3: Calculate final score
const totalScore = (research.scores.demand + research.scores.competition) / 2;
research.totalScore = totalScore;
// Step 4: Generate recommendation
console.log(`\n${'='.repeat(60)}`);
console.log('FINAL RECOMMENDATION');
console.log(`${'='.repeat(60)}\n`);
console.log(`Demand Score: ${research.scores.demand}/100`);
console.log(`Competition Score: ${research.scores.competition}/100`);
console.log(`Overall Score: ${totalScore.toFixed(1)}/100\n`);
if (totalScore >= 70) {
research.recommendation = '🌟 HIGHLY RECOMMENDED - Great opportunity';
} else if (totalScore >= 50) {
research.recommendation = '✅ RECOMMENDED - Good potential';
} else if (totalScore >= 30) {
research.recommendation = '⚠️ PROCEED WITH CAUTION - Test small first';
} else {
research.recommendation = '❌ NOT RECOMMENDED - Skip this product';
}
console.log(`Recommendation: ${research.recommendation}`);
this.products.push(research);
return research;
} catch (error) {
console.error('Research failed:', error.message);
return null;
}
}
scoreDemand(analysis) {
if (!analysis) return 0;
let score = 0;
// High average views = high demand
if (analysis.avgViews > 100000) score += 40;
else if (analysis.avgViews > 50000) score += 30;
else if (analysis.avgViews > 10000) score += 20;
// High engagement = product interest
if (analysis.avgComments > 500) score += 30;
else if (analysis.avgComments > 200) score += 20;
else if (analysis.avgComments > 50) score += 10;
// Multiple creators = validated market
if (analysis.creators && analysis.creators.size > 20) score += 30;
else if (analysis.creators && analysis.creators.size > 10) score += 20;
else if (analysis.creators && analysis.creators.size > 5) score += 10;
return Math.min(score, 100);
}
scoreCompetition(analysis) {
if (!analysis) return 0;
let score = 100;
// Lower competition = higher score
if (analysis.totalCreators > 100) score -= 50;
else if (analysis.totalCreators > 50) score -= 30;
else if (analysis.totalCreators > 20) score -= 10;
// Check if top competitors dominate
if (analysis.topCompetitors && analysis.topCompetitors.length > 0) {
const topCreator = analysis.topCompetitors[0];
if (topCreator.followers > 100000) score -= 20; // Hard to compete with big creators
}
return Math.max(score, 0);
}
getTopProducts(limit = 5) {
return this.products
.sort((a, b) => b.totalScore - a.totalScore)
.slice(0, limit);
}
}
// Usage
const researcher = new ProductResearcher();
// Research multiple products
await researcher.researchProduct('portable blender');
await researcher.researchProduct('neck fan');
await researcher.researchProduct('phone holder');
// Get top opportunities
const topProducts = researcher.getTopProducts(3);
console.log('\n=== TOP PRODUCT OPPORTUNITIES ===\n');
topProducts.forEach((product, i) => {
console.log(`${i + 1}. ${product.keyword} (Score: ${product.totalScore.toFixed(1)}/100)`);
console.log(` ${product.recommendation}\n`);
});
Real Product Research Success
Example 1: Found Winning Product
Product: Portable neck fan Research showed:
- Growing hashtag (150% week-over-week growth)
- Only 18 active sellers
- Average 85K views per video
- High engagement (8% engagement rate)
Decision: Ordered 200 units Result: Sold out in 11 days, $3,200 profit
Example 2: Avoided Money Pit
Product: Portable blender (saw it going viral) Research showed:
- 240 active sellers (saturated)
- Declining growth rate
- Price war (sellers dropping to $19.99)
- Thin profit margins
Decision: Skipped it Result: Saved $3,500 in inventory costs
Your Product Research Action Plan
- Build product watchlist - Add 20 potential products
- Run daily analysis - Check growth trends
- Calculate profit margins - Must be above $10 per unit
- Check competition - Under 50 sellers is ideal
- Test with small order - Start with 50-100 units
- Scale winners - Reorder products that sell
Get your SociaVault API key and start researching products with data. Know what will sell before you buy inventory.
Stop guessing. Start researching.
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API