Q1 2026 · Full Keyword Report

E-commerce CPC Benchmarks

Loading data...
Median CPC
Google Search
CPC Range
p25 – p75
Avg Competition
0 = none · 1 = max
Keywords
Google Search Ads
Sample keywords
Showing 5 of · Unlock full report below
Keyword CPC Volume/mo Competition Opportunity
See all keywords
Unlock 80+ Google Search keywords with CPC, volume, competition score, and opportunity ranking. Permanent access — data updates quarterly.
One-time purchase · No subscription
Unlock E-commerce Report — $49
or
+ v.toFixed(2) : '—'; const googleCpcs = byPlatform.google_search.sort((a,b)=>a-b); const p25 = googleCpcs.length ? googleCpcs[Math.floor(googleCpcs.length*0.25)] : null; const p75 = googleCpcs.length ? googleCpcs[Math.floor(googleCpcs.length*0.75)] : null; const avgComp = data.filter(r=>r.competition!=null).map(r=>Number(r.competition)); const avgCompVal = avgComp.length ? avgComp.reduce((a,b)=>a+b,0)/avgComp.length : null; document.getElementById('stat-g-cpc').textContent = fmt(median(byPlatform.google_search)); document.getElementById('stat-cpc-range').textContent = p25 && p75 ? fmt(p25)+' – '+fmt(p75) : '—'; document.getElementById('stat-competition').textContent = avgCompVal != null ? avgCompVal.toFixed(2) : '—'; document.getElementById('stat-count').textContent = data.length; const totalKeywords = data.length; document.getElementById('total-count').textContent = totalKeywords; document.getElementById('report-meta').innerHTML = ` 📊 ${totalKeywords} keywords 🕐 Q1 2026 data ✓ DataForSEO sourced 3 platforms: Google · Meta · TikTok `; } function renderPreviewRows(data) { const tbody = document.getElementById('preview-tbody'); tbody.innerHTML = data.map(row => buildRow(row)).join(''); } async function tryUnlock(token) { // Validate token against DB const res = await fetch(SUPABASE_URL + '/rest/v1/rpc/validate_report_token', { method: 'POST', headers: { 'apikey': SUPABASE_ANON_KEY, 'Authorization': 'Bearer ' + SUPABASE_ANON_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ p_token: token }) }); if (!res.ok) { showTokenError('Could not verify token. Please try again.'); await loadPreview(); return; } const _rpcData = await res.json(); const result = Array.isArray(_rpcData) ? _rpcData[0] : _rpcData; if (!result || !result.valid) { showTokenError('Invalid or expired token. Check your purchase email.'); await loadPreview(); return; } // Check if this token grants access to this industry const hasAccess = result.product_type === 'bundle_all' || result.product_type === 'bundle_complete' || result.industry_slug === REPORT_CONFIG.industry_slug; if (!hasAccess) { showTokenError(`This token is for ${result.industry_name}, not ${REPORT_CONFIG.industry_name}.`); await loadPreview(); return; } // Token valid — load full dataset await loadFullReport(token); } async function loadFullReport(token) { // Load all keywords for this industry const res = await supabaseFetch( `/rest/v1/keywords?select=term,anchor_cpc,anchor_cpm,anchor_ctr,volume,competition,verified_crowd_cpc,total_valid_reports,last_updated,platforms!inner(name,display_name),industries!inner(slug)` + `&industries.slug=eq.${REPORT_CONFIG.industry_slug}&limit=2000` ); if (!res.ok) { showTokenError('Data fetch failed. Refresh to try again.'); return; } const data = await res.json(); // Enrich with opportunity score allKeywords = data.map(row => { const cpc = Number(row.anchor_cpc) || 0; const vol = Number(row.volume) || 0; const comp = Number(row.competition) || 0; return { ...row, platform_name: row.platforms?.name ?? '', platform_display: row.platforms?.display_name ?? '', opportunity_score: cpc > 0 ? Math.round((vol * (1 - comp)) / cpc) : 0 }; }); // Hide paywall, show full report document.getElementById('paywall').style.display = 'none'; document.getElementById('full-report').style.display = 'block'; document.getElementById('preview-label').textContent = `Showing ${allKeywords.length} keywords — access unlocked`; await loadStats(); renderTable(); renderGems(); } function setTab(tab, btn) { currentTab = tab; document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); btn.classList.add('active'); renderTable(); } function sortBy(col) { if (currentSort.col === col) { currentSort.dir = currentSort.dir === 'asc' ? 'desc' : 'asc'; } else { currentSort.col = col; currentSort.dir = col === 'anchor_cpc' || col === 'competition' || col === 'anchor_cpm' ? 'asc' : 'desc'; } document.querySelectorAll('th').forEach(th => th.classList.remove('sorted')); event?.currentTarget?.classList.add('sorted'); renderTable(); } function renderTable() { const search = document.getElementById('search-input')?.value?.toLowerCase() ?? ''; const sortVal = document.getElementById('sort-select')?.value ?? 'volume'; let rows = allKeywords.filter(row => { const matchPlatform = currentTab === 'all' || row.platform_name === currentTab; const matchSearch = !search || row.term.toLowerCase().includes(search); return matchPlatform && matchSearch; }); // Sort const [sortCol, sortDir] = sortVal.endsWith('_desc') ? [sortVal.replace('_desc', ''), 'desc'] : [sortVal, 'asc']; rows.sort((a, b) => { let av = a[sortCol] ?? 0, bv = b[sortCol] ?? 0; if (typeof av === 'string') return sortDir === 'asc' ? av.localeCompare(bv) : bv.localeCompare(av); return sortDir === 'asc' ? av - bv : bv - av; }); document.getElementById('full-tbody').innerHTML = rows.map(row => buildRow(row)).join(''); document.getElementById('kw-count').textContent = `${rows.length} keywords`; } function renderGems() { const google = allKeywords .filter(r => r.platform_name === 'google_search' && r.opportunity_score > 0) .sort((a, b) => b.opportunity_score - a.opportunity_score) .slice(0, 10); const danger = allKeywords .filter(r => r.platform_name === 'google_search') .sort((a, b) => b.anchor_cpc - a.anchor_cpc) .slice(0, 10); const gemCard = (row, i, mode) => `
#${i+1} ${mode === 'gem' ? '★ Hidden Gem' : '⚠ Avoid if budget-limited'}
${row.term}
CPC $${Number(row.anchor_cpc).toFixed(2)}
Vol ${Number(row.volume||0).toLocaleString()}
Comp ${Number(row.competition||0).toFixed(2)}
${mode === 'gem' ? `
Opp ${row.opportunity_score.toLocaleString()}
` : ''}
`; document.getElementById('gems-grid').innerHTML = google.map((r,i) => gemCard(r, i, 'gem')).join(''); document.getElementById('danger-grid').innerHTML = danger.map((r,i) => gemCard(r, i, 'danger')).join(''); } function buildRow(row) { const cpc = row.anchor_cpc != null ? '$' + Number(row.anchor_cpc).toFixed(2) : '—'; const cpm = row.anchor_cpm != null ? '$' + Number(row.anchor_cpm).toFixed(2) : '—'; const ctr = row.anchor_ctr != null ? (Number(row.anchor_ctr) * 100).toFixed(1) + '%' : '—'; const vol = row.volume ? Number(row.volume).toLocaleString() : '—'; const comp = row.competition != null ? Number(row.competition) : null; const compBar = comp != null ? `
${comp.toFixed(2)}
` : '—'; const opp = row.opportunity_score != null ? row.opportunity_score : null; const oppStars = opp != null ? `${opp > 500 ? '★★★' : opp > 100 ? '★★☆' : '★☆☆'} ${opp.toLocaleString()}` : '—'; const crowd = row.verified_crowd_cpc ? `$${Number(row.verified_crowd_cpc).toFixed(2)} (${row.total_valid_reports})` : '—'; const platDisplay = row.platforms?.display_name ?? row.platform_display ?? ''; return ` ${row.term} ${cpc} ${vol} ${compBar} ${oppStars} ${crowd} `; } function unlockWithToken() { const token = document.getElementById('token-field')?.value?.trim(); if (!token) return; const params = new URLSearchParams(window.location.search); params.set('token', token); window.location.search = params.toString(); } function showTokenError(msg) { const field = document.getElementById('token-field'); if (field) { field.style.borderColor = 'var(--danger)'; field.placeholder = msg; field.value = ''; } } async function supabaseFetch(path, method = 'GET') { return fetch(SUPABASE_URL + path, { method, headers: { 'apikey': SUPABASE_ANON_KEY, 'Authorization': 'Bearer ' + SUPABASE_ANON_KEY, } }); }