const { useMemo, useState, useEffect } = React; const PINK = "#ff4fa3"; const BLUE = "#4f8bff"; const fav = (domain) => `https://www.google.com/s2/favicons?domain=${domain}&sz=64`; const host = (url) => { try { return new URL(url).hostname; } catch { return url; } }; // ErrorBoundary to avoid blank screens class ErrorBoundary extends React.Component{ constructor(props){ super(props); this.state={hasError:false, error:null}; } static getDerivedStateFromError(error){ return {hasError:true, error}; } componentDidCatch(error, info){ console.error("CamCompare Error:", error, info); } render(){ if(this.state.hasError){ return (
Something went wrong loading this section.
Please reload the page. If it persists, re-install the plugin zip v17.4.
); } return this.props.children; } } // Data (includes customer metrics + deals) const PLATFORMS = [ { name: "Flirt4Free", site: "https://f4f.link/m/340677", ratePct: 60, payout: "Weekly", payoutMin: "$50", payoutMethods:["SEPA","SWIFT"], payoutFees:"Varies", estCustomersK: 3000, estModelsK: 150, features:{ vod:true, lovense:true, ppvClips:true, vr:false, mobileApp:true, twoFA:true, geoBlocking:true }, notes:"Established network with tipping, shows & VOD.", customer:{ pricePerTokenUSD:0.10, valueForMoney:4.1, modelDiversity:["Women","Men","Couples"], activeModelsK:12, privatePerMinUSD:2.99, groupPerMinUSD:1.49, videoQuality:"HD/4K", interactive:["Cam2Cam","Lovense","Games"], freeContent:"Medium", uiNavigation:4.4, privacySecurity:["SSL","2FA"], payments:["Cards","Crypto"], reviewsScore:4.3, support:"24/7 chat", perks:["Welcome credits"] }, deals:{ model:{ headline:"Signup boost", perks:["Faster verification","Weekly payouts"], code:null, link:"https://jayson-d.flirt4free.com" }, customer:{ signupBonus:"Welcome credits", welcomeCredits:20, creditBonusPct:10, bundles:["$20 → $22","$50 → $55"], finePrint:"Promos vary by region; limited time.", code:null, link:"https://jayson-d.flirt4free.com" } } }, { name: "OnlyFans (Live)", site: "https://onlyfans.com?ref=517803888", ratePct: 80, payout: "Weekly", payoutMin: "$50", payoutMethods:["SEPA","SWIFT"], payoutFees:"Medium", estCustomersK: 12000, estModelsK: 1500, features:{ vod:true, lovense:true, ppvClips:true, vr:false, mobileApp:true, twoFA:true, geoBlocking:true }, notes:"Huge user base; live exists but discovery is limited vs cam sites.", customer:{ pricePerTokenUSD:0.10, valueForMoney:4.0, modelDiversity:["Women","Men","NB","Trans","Couples"], activeModelsK:40, privatePerMinUSD:3.99, groupPerMinUSD:1.99, videoQuality:"HD", interactive:["Cam2Cam","Lovense"], freeContent:"Low", uiNavigation:4.2, privacySecurity:["SSL","2FA"], payments:["Cards"], reviewsScore:4.2, support:"Email", perks:["Fan clubs","Clips"] }, deals:{ model:{ headline:"Creator promo", perks:["80% revenue share","Bonuses vary"], code:null, link:"https://onlyfans.com?ref=517803888" }, customer:{ signupBonus:"Occasional discounts", welcomeCredits:0, creditBonusPct:0, bundles:["Seasonal sales"], finePrint:"Offers vary by creator/site campaigns.", code:null, link:"https://onlyfans.com?ref=517803888" } } }, { name: "BongaCams", site: "https://bongacash.com/model-ref?c=827213", ratePct: 60, payout: "Weekly", payoutMin: "$50", payoutMethods:["SEPA","SWIFT"], payoutFees:"Low", estCustomersK: 6500, estModelsK: 400, features:{ vod:true, lovense:true, ppvClips:false, vr:false, mobileApp:false, twoFA:true, geoBlocking:true }, notes:"High exposure in EU markets, weekly payouts.", customer:{ pricePerTokenUSD:0.10, valueForMoney:4.3, modelDiversity:["Women","Men","Trans"], activeModelsK:18, privatePerMinUSD:2.49, groupPerMinUSD:1.29, videoQuality:"HD", interactive:["Lovense","Games"], freeContent:"High", uiNavigation:4.0, privacySecurity:["SSL","2FA"], payments:["Cards","Crypto"], reviewsScore:4.1, support:"24/7 chat", perks:["Bonuses"] }, deals:{ model:{ headline:"Model signup perks", perks:["EU traffic boost","Weekly payouts"], code:null, link:"https://bongacash.com/model-ref?c=827213" }, customer:{ signupBonus:"Welcome credits", welcomeCredits:30, creditBonusPct:15, bundles:["$20 → $23","$50 → $57.5"], finePrint:"Bonus auto‑applies on selected packs.", code:null, link:"https://bongacams.com" } } }, { name: "Fansly (Live)", site: "https://fansly.com/application/form?r=comparecamsites", ratePct: 80, payout: "Weekly", payoutMin: "$100", payoutMethods:["SEPA","SWIFT"], payoutFees:"Medium", estCustomersK: 1500, estModelsK: 90, features:{ vod:true, lovense:true, ppvClips:true, vr:false, mobileApp:true, twoFA:true, geoBlocking:true }, notes:"Sub/PPV focus with live add-on.", customer:{ pricePerTokenUSD:0.10, valueForMoney:3.9, modelDiversity:["Women","Men","NB","Trans"], activeModelsK:6, privatePerMinUSD:3.49, groupPerMinUSD:1.59, videoQuality:"HD", interactive:["Lovense"], freeContent:"Low", uiNavigation:4.0, privacySecurity:["SSL","2FA"], payments:["Cards"], reviewsScore:4.0, support:"Ticket", perks:["Clips"] }, deals:{ model:{ headline:"New creator ramp", perks:["80% share","Tier promos"], code:null, link:"https://fansly.com/application/form?r=comparecamsites" }, customer:{ signupBonus:"Seasonal promo", welcomeCredits:10, creditBonusPct:5, bundles:["Creator bundles"], finePrint:"Creator‑specific discounts may apply.", code:null, link:"https://fansly.com/comparewebcamsites?r=comparewebcamsites" } } }, { name: "Chaturbate", site: "http://chaturbate.com/accounts/register/?studio=jjaysond", ratePct: 50, payout: "Weekly", payoutMin: "$50", payoutMethods:["SEPA","SWIFT","Crypto"], payoutFees:"Varies", estCustomersK: 8000, estModelsK: 500, features:{ vod:true, lovense:true, ppvClips:true, vr:false, mobileApp:true, twoFA:true, geoBlocking:true }, notes:"Token-based, strong traffic, robust Lovense support.", customer:{ pricePerTokenUSD:0.10, valueForMoney:4.4, modelDiversity:["Women","Men","Couples","Trans"], activeModelsK:22, privatePerMinUSD:2.99, groupPerMinUSD:1.49, videoQuality:"HD/4K", interactive:["Cam2Cam","Lovense","Games"], freeContent:"High", uiNavigation:4.5, privacySecurity:["SSL","2FA"], payments:["Cards","Crypto"], reviewsScore:4.5, support:"24/7 chat", perks:["Teasers"] }, deals:{ model:{ headline:"Fast-track start", perks:["Weekly payouts","High traffic"], code:null, link:"http://chaturbate.com/accounts/register/?studio=jjaysond" }, customer:{ signupBonus:"Token sales", welcomeCredits:0, creditBonusPct:10, bundles:["$20 → $22","$100 → $110"], finePrint:"Frequent rotating sales; check banner.", code:null, link:"https://chaturbate.com/in/?tour=grq0&campaign=tRJ0r&track=default" } } }, { name: "MyFreeCams", site: "https://t.amyfc.link/388186/779/0?bo=2779,2778,2777,2776,2775&po=6533&aff_sub5=SF_006OG000004lmDN", ratePct: 60, payout: "Bi-weekly", payoutMin: "$100", payoutMethods:["SWIFT"], payoutFees:"Medium", estCustomersK: 4200, estModelsK: 220, features:{ vod:false, lovense:true, ppvClips:false, vr:false, mobileApp:false, twoFA:true, geoBlocking:true }, notes:"Established brand; member culture heavy.", customer:{ pricePerTokenUSD:0.10, valueForMoney:3.8, modelDiversity:["Women","Couples"], activeModelsK:10, privatePerMinUSD:2.49, groupPerMinUSD:1.19, videoQuality:"HD", interactive:["Lovense"], freeContent:"Medium", uiNavigation:3.9, privacySecurity:["SSL","2FA"], payments:["Cards"], reviewsScore:4.0, support:"Email", perks:["Clubs"] }, deals:{ model:{ headline:"Standard onboarding", perks:["Community-centric"], code:null, link:"https://t.amyfc.link/388186/779/0?bo=2779,2778,2777,2776,2775&po=6533&aff_sub5=SF_006OG000004lmDN" }, customer:{ signupBonus:"VIP promos", welcomeCredits:0, creditBonusPct:5, bundles:["VIP club perks"], finePrint:"Promos vary; see site.", code:null, link:"https://t.amyfc.link/388186/779/0?bo=2779,2778,2777,2776,2775&po=6533&aff_sub5=SF_006OG000004lmDN" } } }, { name: "Stripchat", site: "https://go.rmhfrtnd.com?path=%2Fsignup%2Fuser&userId=28301efbaad60d0dce6cbe01d0ba21e5d5dbb61b85ad4b2a66eaa0c9d49dbd80", ratePct: 60, payout: "Weekly", payoutMin: "$100", payoutMethods:["SEPA","SWIFT","Crypto"], payoutFees:"Varies", estCustomersK: 7000, estModelsK: 350, features:{ vod:true, lovense:true, ppvClips:true, vr:true, mobileApp:true, twoFA:true, geoBlocking:true }, notes:"Modern UX, VR shows, strong discoverability.", customer:{ pricePerTokenUSD:0.10, valueForMoney:4.5, modelDiversity:["Women","Men","Trans","Couples"], activeModelsK:20, privatePerMinUSD:2.99, groupPerMinUSD:1.49, videoQuality:"HD/4K", interactive:["Cam2Cam","Lovense","VR"], freeContent:"Medium", uiNavigation:4.6, privacySecurity:["SSL","2FA"], payments:["Cards","Crypto"], reviewsScore:4.4, support:"24/7 chat", perks:["Welcome credits","Multilingual"] }, deals:{ model:{ headline:"Launch perks", perks:["VR support","Weekly payouts"], code:null, link:"https://go.rmhfrtnd.com?path=%2Fsignup%2Fuser&userId=28301efbaad60d0dce6cbe01d0ba21e5d5dbb61b85ad4b2a66eaa0c9d49dbd80" }, customer:{ signupBonus:"Welcome pack", welcomeCredits:25, creditBonusPct:10, bundles:["$20 → $22","$50 → $55"], finePrint:"Regional restrictions apply.", code:null, link:"https://go.rmhfrtnd.com?path=%2Fsignup%2Fuser&userId=28301efbaad60d0dce6cbe01d0ba21e5d5dbb61b85ad4b2a66eaa0c9d49dbd80" } } }, { name: "CamSoda", site: "https://www.camsoda.com/models?id=comparecamsites", ratePct: 50, payout: "Weekly", payoutMin: "$50", payoutMethods:["SEPA","SWIFT","ACH"], payoutFees:"Low", estCustomersK: 2300, estModelsK: 120, features:{ vod:true, lovense:true, ppvClips:true, vr:true, mobileApp:true, twoFA:true, geoBlocking:true }, notes:"Tech-forward, interactive toys & VR.", customer:{ pricePerTokenUSD:0.10, valueForMoney:4.0, modelDiversity:["Women","Men","Trans"], activeModelsK:8, privatePerMinUSD:2.79, groupPerMinUSD:1.39, videoQuality:"HD/4K", interactive:["Lovense","VR"], freeContent:"Medium", uiNavigation:4.1, privacySecurity:["SSL","2FA"], payments:["Cards"], reviewsScore:4.1, support:"Chat", perks:["Clips"] }, deals:{ model:{ headline:"Model incentives", perks:["VR ready","Weekly payouts"], code:null, link:"https://www.camsoda.com/models?id=comparecamsites" }, customer:{ signupBonus:"Occasional credits", welcomeCredits:15, creditBonusPct:10, bundles:["Bundles & sales"], finePrint:"Rotating promos; check homepage.", code:null, link:"https://www.camsoda.com/?id=comparecamsites&type=REV" } } }, ].map(p => ({ ...p, logo: fav(host(p.site)) })); // Webcams & Toys — images + purchase links const WEBCAMS = [ { name: "Logitech Brio 4K", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/webcam_resized_with_border.png", buyUrl: "https://amzn.to/42gRti0" }, { name: "Elgato Facecam", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Elgato-Facecam.png", buyUrl: "https://amzn.to/4niw00o" }, { name: "Razer Kiyo Pro", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Razer-Kiyo-Pro.png", buyUrl: "https://amzn.to/4mNyu6Z" }, { name: "Insta360 Link", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Insta360-Link.png", buyUrl: "https://amzn.to/3VCbJHb" }, { name: "OBSBOT Tiny", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/OBSBOT-Tiny.png", buyUrl: "https://amzn.to/4m7g1kR" }, { name: "Logitech StreamCam", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Logitech-StreamCam.png", buyUrl: "https://amzn.to/41FqkFt" }, ]; const TOYS = [ { name: "Lovense Lush 3", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Lush-3.png", buyUrl: "https://www.lovense.com/r/cjco0x" }, { name: "Lovense Lush 2", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Lush-2.png", buyUrl: "https://www.lovense.com/r/qs7tch" }, { name: "Lovense Edge 2", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Edge-2-.png", buyUrl: "https://www.lovense.com/r/oq5l4l" }, { name: "Lovense Lush Mini", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Lush-Mini.png", buyUrl: "https://www.lovense.com/r/ojrz7e" }, { name: "Lovense Nora", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Nora.png", buyUrl: "https://www.lovense.com/r/u2iy44" }, { name: "Lovense Domi 2", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Domi-2.png", buyUrl: "https://www.lovense.com/r/3djzqa" }, { name: "Lovense Gush", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Gush.png", buyUrl: "https://www.lovense.com/r/vuip60" }, { name: "Lovense Gush 2", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Gush-2.png", buyUrl: "https://www.lovense.com/r/510u5l" }, { name: "Lovense Mission 2", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Mission-2.png", buyUrl: "https://www.lovense.com/r/cel34c" }, { name: "Lovense Gravity", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Gravity-Sex-Toy.png", buyUrl: "https://www.lovense.com/r/wmaufk" }, { name: "Lovense Lush 4", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Lovense-Lush-4.png", buyUrl: "https://www.lovense.com/r/qs7tch" }, { name: "Solace Pro", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Solace-Pro.png", buyUrl: "https://www.lovense.com/r/v1brkw" }, { name: "Solace Max 2", img: "https://comparewebcamsites.com/wp-content/uploads/2025/09/Solace-Max-2-Toy.png", buyUrl: "https://www.lovense.com/r/ntajpt" }, ]; function Tag({ children }){ return {children}; } function Pill({ active, label, onClick }){ return ; } function Range({ label, value, onChange, min, max, step=1, suffix="" }){ return (
{label}{value}{suffix}
onChange(Number(e.target.value))} className="w-full accent-blue-500" />
); } function NumberInput({ label, value, onChange, min, max, step=1 }){ return (
{label}
onChange(Number(e.target.value))} />
); } function Card({ children }){ return
{children}
; } // ---------------- Mode-aware filters ---------------- function useModelFilters(){ const [f,setF]=useState({ query:"", minRate:40, minCustomersK:0, maxCustomersK:20000, minModelsK:0, maxModelsK:2000, feat:{ vod:false, lovense:false, ppvClips:false, vr:false, mobileApp:false, twoFA:false, geoBlocking:false }, payoutFilters:[], sortBy:"score" }); return [f,setF]; } function useCustomerFilters(){ const [f,setF]=useState({ query:"", tokenMin:0.05, tokenMax:0.20, privateMax:4.00, groupMax:2.00, minValue:0.0, payments:{ Cards:false, Crypto:false }, interactive:{ "Cam2Cam":false, "Lovense":false, "VR":false }, freeContent:{ Low:false, Medium:false, High:false }, sortBy:"value" }); return [f,setF]; } function filterModelRows(filters){ const q=(filters.query||"").toLowerCase().trim(); let rows=PLATFORMS.filter(p=>{ const matches=!q||p.name.toLowerCase().includes(q); const withinRate=p.ratePct>=filters.minRate; const withinCustomers=p.estCustomersK>=filters.minCustomersK&&p.estCustomersK<=filters.maxCustomersK; const withinModels=p.estModelsK>=filters.minModelsK&&p.estModelsK<=filters.maxModelsK; const featOK=Object.entries(filters.feat).every(([k,v])=> v? p.features[k]: true); const payoutOK=filters.payoutFilters.length===0 || filters.payoutFilters.includes(p.payout); return matches&&withinRate&&withinCustomers&&withinModels&&featOK&&payoutOK; }).map(p=>({...p, earningsPer100:(p.ratePct/100)*100, score:p.ratePct*0.5 + p.estCustomersK*0.004 + p.estModelsK*0.03 + (p.features.lovense?2:0) + (p.features.vr?1:0)})); const sorter={ score:(a,b)=>b.score-a.score, rate:(a,b)=>b.ratePct-a.ratePct, customers:(a,b)=>b.estCustomersK-a.estCustomersK, models:(a,b)=>b.estModelsK-a.estModelsK, name:(a,b)=>a.name.localeCompare(b.name) }[filters.sortBy] || ((a,b)=>0); rows.sort(sorter); return rows; } function filterCustomerRows(filters){ const q=(filters.query||"").toLowerCase().trim(); let rows=PLATFORMS.filter(p=>{ const c=p.customer||{}; if(!(!q || p.name.toLowerCase().includes(q))) return false; if(!(c.pricePerTokenUSD>=filters.tokenMin && c.pricePerTokenUSD<=filters.tokenMax)) return false; if(!(c.privatePerMinUSD<=filters.privateMax)) return false; if(!(c.groupPerMinUSD<=filters.groupMax)) return false; if(!(c.valueForMoney>=filters.minValue)) return false; for(const k of Object.keys(filters.payments)){ if(filters.payments[k] && !(c.payments||[]).includes(k)) return false; } for(const k of Object.keys(filters.interactive)){ if(filters.interactive[k] && !(c.interactive||[]).includes(k)) return false; } const selectedFC = Object.keys(filters.freeContent).filter(k=>filters.freeContent[k]); if(selectedFC.length>0 && !selectedFC.includes(String(c.freeContent))) return false; return true; }).map(p=>({...p, ...p.customer})); const sorter={ value:(a,b)=> b.valueForMoney-a.valueForMoney || b.activeModelsK-a.activeModelsK, token:(a,b)=> a.pricePerTokenUSD-b.pricePerTokenUSD, private:(a,b)=> a.privatePerMinUSD-b.privatePerMinUSD, group:(a,b)=> a.groupPerMinUSD-b.groupPerMinUSD, active:(a,b)=> b.activeModelsK-a.activeModelsK, name:(a,b)=> a.name.localeCompare(b.name) }[filters.sortBy] || ((a,b)=>0); rows.sort(sorter); return rows; } // ---------------- Drawer with vertical tab ---------------- function FilterDrawer({ open, setOpen, mode, modelFilters, setModelFilters, customerFilters, setCustomerFilters }){ const setFeat=(k,v)=> setModelFilters(f=>({...f, feat:{...f.feat,[k]:v}})); const togglePayout=(val)=> setModelFilters(f=>({...f, payoutFilters: f.payoutFilters.includes(val)? f.payoutFilters.filter(x=>x!==val) : [...f.payoutFilters,val]})); const PAYOUT_OPTIONS = Array.from(new Set(PLATFORMS.map(p=>p.payout))); const Tab = ( ); return (<> {Tab} {open &&
setOpen(false)} />}

Filters — {mode==="model"?"For Models":"For Customers"}

{mode==="model" ? (<>
Search
setModelFilters(f=>({...f, query:e.target.value}))} />
setModelFilters(f=>({...f,minRate:v}))} />
setModelFilters(f=>({...f,minCustomersK:v}))} min={0} max={20000} step={100} /> setModelFilters(f=>({...f,maxCustomersK:v}))} min={0} max={20000} step={100} />
setModelFilters(f=>({...f,minModelsK:v}))} min={0} max={2000} step={10} /> setModelFilters(f=>({...f,maxModelsK:v}))} min={0} max={2000} step={10} />
Features
{Object.keys(modelFilters.feat).map(k=> setModelFilters(f=>({...f, feat:{...f.feat, [k]:!f.feat[k]}}))} />)}
Payout timeframe
{PAYOUT_OPTIONS.map(opt=> togglePayout(opt)} />)}
Sort by
) : (<>
Search
setCustomerFilters(f=>({...f, query:e.target.value}))} />
setCustomerFilters(f=>({...f, tokenMax:Number(v.toFixed(2))}))} /> setCustomerFilters(f=>({...f, privateMax:Number(v.toFixed(1))}))} /> setCustomerFilters(f=>({...f, groupMax:Number(v.toFixed(2))}))} /> setCustomerFilters(f=>({...f, minValue:Number(v.toFixed(1))}))} />
Payments
{["Cards","Crypto"].map(k=> setCustomerFilters(f=>({...f, payments:{...f.payments, [k]:!f.payments[k]}}))} />)}
Interactive
{["Cam2Cam","Lovense","VR"].map(k=> setCustomerFilters(f=>({...f, interactive:{...f.interactive, [k]:!f.interactive[k]}}))} />)}
Free content
{["Low","Medium","High"].map(k=> setCustomerFilters(f=>({...f, freeContent:{...f.freeContent, [k]:!f.freeContent[k]}}))} />)}
Sort by
)}
); } // ---------------- Tables ---------------- function ModelTable({ rows, onToggleSave, onToggleCompare, saved, compare }){ return (
{rows.map((p,idx)=> ())}
Platform Rev % Per $100 Payout Cust (K) Models (K) Lovense VOD PPV VR App 2FA Geo Actions Link
{`${p.name}
{p.name}
{p.notes}
{p.ratePct}% ${p.earningsPer100.toFixed(0)} {p.payout} {p.estCustomersK.toLocaleString()}K {p.estModelsK.toLocaleString()}K {p.features.lovense?"✓":"—"} {p.features.vod?"✓":"—"} {p.features.ppvClips?"✓":"—"} {p.features.vr?"✓":"—"} {p.features.mobileApp?"✓":"—"} {p.features.twoFA?"✓":"—"} {p.features.geoBlocking?"✓":"—"} Visit
); } function CustomerTable({ items }){ const cols=[ { key:"name", label:"Site", align:"left" }, { key:"pricePerTokenUSD", label:"Token $", align:"right", fmt:v=>"$"+v.toFixed(2) }, { key:"privatePerMinUSD", label:"Private/min", align:"right", fmt:v=>"$"+v.toFixed(2) }, { key:"groupPerMinUSD", label:"Group/min", align:"right", fmt:v=>"$"+v.toFixed(2) }, { key:"freeContent", label:"Free Content", align:"center" }, { key:"videoQuality", label:"Quality", align:"center" }, { key:"interactive", label:"Interactive", align:"center", fmt:v=>Array.isArray(v)? v.slice(0,3).join(" · "):v }, { key:"payments", label:"Payments", align:"center", fmt:v=>Array.isArray(v)? v.join(", "):v }, { key:"activeModelsK", label:"Active (K)", align:"right", fmt:v=>v+"K" }, { key:"valueForMoney", label:"Value/5", align:"right", fmt:v=>v.toFixed(1) }, { key:"link", label:"Visit", align:"right", action:true }, ]; const itemsSorted = items.slice(); return (
{cols.map(c=> )}{itemsSorted.map((p,i)=> ({ cols.map(c=>{ let content=null; const cls=`${c.align==="right"?"text-right":c.align==="center"?"text-center":"text-left"} px-4 py-3`; if(c.key==="name") content=
logo{p.name}
; else if(c.action) content=Visit; else { const v=p[c.key]; content=c.fmt? c.fmt(v) : (Array.isArray(v) ? v.join(", ") : v); } return ; }) }))}
{c.label}
{content}

All figures are accurate at the time of updating (07/09/2025).

); } // ---------------- Calculators ---------------- function ModelCalculator(){ const [platform, setPlatform] = useState(PLATFORMS[0].name); const [viewers, setViewers] = useState(200); const [tippersPct, setTippersPct] = useState(5); const [avgTip, setAvgTip] = useState(10); const [hoursPerDay, setHoursPerDay] = useState(4); const [daysPerWeek, setDaysPerWeek] = useState(5); const ratePct = PLATFORMS.find(p=>p.name===platform)?.ratePct ?? 60; const tipsPerHour = viewers*(tippersPct/100)*avgTip; const takeHomePerHour = tipsPerHour*(ratePct/100); const daily = takeHomePerHour*hoursPerDay; const weekly = daily*daysPerWeek; return (

Earnings Calculator (Models)

Platform
You keep per $100 tips
${((ratePct/100)*100).toFixed(0)}
Take-home per hour
${takeHomePerHour.toFixed(2)}
Estimated daily (net)
${daily.toFixed(2)}
Estimated weekly (net)
${weekly.toFixed(2)}
); } function CustomerCalculator(){ const [platform, setPlatform] = useState(PLATFORMS[0].name); const p = PLATFORMS.find(x=>x.name===platform) || {}; const c = p.customer || {}; const [budget, setBudget] = useState(50); const [tipSize, setTipSize] = useState(5); const tokenPrice = c.pricePerTokenUSD ?? 0.10; const privatePerMin = c.privatePerMinUSD ?? 2.99; const groupPerMin = c.groupPerMinUSD ?? 1.49; const tokens = Math.floor(budget / tokenPrice); const privateMins = privatePerMin? (budget/privatePerMin): 0; const groupMins = groupPerMin? (budget/groupPerMin): 0; const tipsCount = tipSize? Math.floor(budget/tipSize): 0; return (

Viewer Budget Planner (Customers)

Site
Budget (USD)
setBudget(Number(e.target.value)||0)} />
Average tip size (USD)
setTipSize(Number(e.target.value)||1)} />
Token price: ${tokenPrice.toFixed(2)}
Private/min: ${privatePerMin.toFixed(2)}
Group/min: ${groupPerMin.toFixed(2)}
Tokens you can buy
{tokens.toLocaleString()}
Approx. private minutes
{privateMins.toFixed(1)} min
Approx. group minutes
{groupMins.toFixed(1)} min
Number of tips (avg)
{tipsCount.toLocaleString()}

Estimates assume constant prices; sites vary by room/model.

); } // ---------------- Views ---------------- function PlatformsView({ mode, saved, compare, onToggleSave, onToggleCompare }){ const [modelFilters,setModelFilters] = useModelFilters(); const [customerFilters,setCustomerFilters] = useCustomerFilters(); const [open,setOpen] = useState(false); const rowsModel = filterModelRows(modelFilters); const rowsCustomer = filterCustomerRows(customerFilters); return (

{(mode==="model"? rowsModel.length : rowsCustomer.length)} platform{(mode==="model"? rowsModel : rowsCustomer).length===1?"":"s"} match

{mode==="model" ? (
Sort by
) : (
Sort by
)}
{mode==="model"? ( ) : ( )}
); } function PayoutsView(){ return (

Payouts & Methods

{PLATFORMS.map((p,i)=> ())}
Platform Timeframe Min Payout Methods Fees Link
logo{p.name}
{p.payout} {p.payoutMin||"—"} {(p.payoutMethods||[]).join(", ")} {p.payoutFees||"—"} Visit

All figures are accurate at the time of updating (07/09/2025).

); } // ---------------- Deals Page ---------------- function DealsView({ mode }){ const colsModel = [ { key:"headline", label:"Offer" }, { key:"perks", label:"Incentives" }, { key:"link", label:"Sign‑up" }, ]; const colsCustomer = [ { key:"signupBonus", label:"Sign‑up bonus" }, { key:"welcomeCredits", label:"Welcome credits" }, { key:"creditBonusPct", label:"Credit bonus %" }, { key:"bundles", label:"Popular bundles" }, { key:"finePrint", label:"Fine print" }, { key:"link", label:"Open" }, ]; const rows = PLATFORMS.map(p=> ({ name:p.name, logo:p.logo, model: p.deals?.model || {}, customer: p.deals?.customer || {} })); const cols = mode==="model"? colsModel : colsCustomer; return (

Latest deals & sign‑up incentives — {mode==="model"?"For Models":"For Customers"}

Switch mode at the top (For Models / For Customers)
{cols.map(c=> )} {rows.map((r,i)=> { const data = mode==="model"? r.model : r.customer; return ( {cols.map(c=>{ let content=null; const v = data[c.key]; if(c.key==="perks"){ content = (v||[]).length?
{v.map((p,idx)=>{p})}
: "—"; } else if(c.key==="bundles"){ content = (v||[]).length? v.join(", ") : "—"; } else if(c.key==="creditBonusPct"){ content = (v||0) ? `${v}%` : "—"; } else if(c.key==="welcomeCredits"){ content = (v||0) ? `${v} credits` : "—"; } else if(c.key==="link"){ const link = data.link || "#"; content = {mode==="model"?"Sign‑up":"Open"}; } else { content = v || "—"; } return ; })} ); })}
Platform{c.label}
logo {r.name}
{content}

Deals placeholders — update with your live promos. Last updated 07/09/2025.

); } // Saved & Compare function SavedView({ saved = [], onToggleSave }) { const items = PLATFORMS.filter((p) => saved.includes(p.name)); if (!items.length) return
No saved platforms yet. On the Platforms tab, tap Save to add some.
; return (
{items.map((p) => (
logo
{p.name}
{p.ratePct}% share · {p.payout}
Visit
))}
); } function CompareView({ compare = [], setCompare }) { const items = PLATFORMS.filter((p) => compare.includes(p.name)); if (!items.length) return
No platforms selected to compare. Go to Platforms and press Compare on up to 3.
; const featCols = ["lovense", "vod", "ppvClips", "vr", "mobileApp", "twoFA", "geoBlocking"]; const remove = (name)=> setCompare(prev=> prev.filter(n=>n!==name)); const clear = ()=> setCompare([]); return (
{items.map((p) => ( ))} {items.map((p) => )} {items.map((p) => )} {items.map((p) => )} {items.map((p) => )} {items.map((p) => )} {items.map((p) => ( ))}
Metric
logo {p.name}
Revenue share{p.ratePct}%
Earn per $100${((p.ratePct/100)*100).toFixed(0)}
Payout{p.payout}
Customers (K){p.estCustomersK.toLocaleString()}K
Models (K){p.estModelsK.toLocaleString()}K
Features
{featCols.map((k) => p.features[k] && {k})}
); } // Webcams & Toys function WebcamsView() { return (
{WEBCAMS.map((w) => ( {`${w.name}

{w.name}

  • Great for streaming
  • Autofocus, low-light friendly
  • USB plug-and-play
1080p+ Autofocus Streamer-ready
Buy now Learn more
))}
); } function ToysView() { return (
{TOYS.map((t) => ( {`${t.name}

{t.name}

  • App + interactive cam support
  • Good battery life
  • Model & audience control modes
Interactive App USB-charge
Buy now Learn more
))}
); } // ---------------- App Shell ---------------- function AppShell(){ const [active,setActive] = useState("platforms"); const [mode,setMode] = useState("model"); const [saved,setSaved] = useState([]); const [compare,setCompare] = useState([]); useEffect(()=>{ try{ setSaved(JSON.parse(localStorage.getItem("cc_saved")||"[]")); setCompare(JSON.parse(localStorage.getItem("cc_compare")||"[]")); }catch(e){} },[]); useEffect(()=>{ try{ localStorage.setItem("cc_saved", JSON.stringify(saved)); }catch(e){} },[saved]); useEffect(()=>{ try{ localStorage.setItem("cc_compare", JSON.stringify(compare)); }catch(e){} },[compare]); const toggle=(setList,name,max=99)=> setList(prev=> prev.includes(name)? prev.filter(n=>n!==name) : [...prev,name].slice(0,max)); return (
CC
Compare Webcam Sites
Find the right platform & kit

Compare cam platforms by earnings, audience & features

Switch between For Models and For Customers to see the table, filters, calculator and deals page change. The left filter tab hides while open and the drawer content changes with the mode.

VODLovenseVRPPVApp
Quick tips
  • Higher revenue share ≠ higher income — traffic matters.
  • Lovense support boosts interactivity and tips.
  • Test 2–4 platforms for 2–4 weeks.
{active==="platforms" && setSaved(s=> s.includes(n)? s.filter(x=>x!==n): [...s,n])} onToggleCompare={(n)=>setCompare(s=> s.includes(n)? s.filter(x=>x!==n): [...s,n].slice(0,3))} />} {active==="payouts" && } {active==="deals" && } {active==="calculator" && (mode==="model"? : )} {active==="compare" && } {active==="saved" && setSaved(s=> s.includes(n)? s.filter(x=>x!==n): [...s,n])} />} {active==="webcams" && } {active==="toys" && }
); } // attach to window for the shortcode boot script window.CamCompareApp = AppShell;