I built two Etsy SEO tools in 14 days — full stack breakdown
I spent the last two weeks building two products targeting the 5M+ Etsy seller market. Here's the honest story — what worked, what didn't, and the full technical stack.
The problem
Most Etsy sellers write listings from a maker's perspective. They describe what they made. Buyers search for what they want to find.
"Handmade ceramic mug, blue, 12oz" gets almost no search traffic.
"Handmade Ceramic Coffee Mug | Blue Stoneware 12oz | Gift for Coffee Lovers" ranks for a dozen buyer searches.
Same product. One gets found. One doesn't.
What I built
ContentBase — AI listing optimizer. Paste any Etsy, Shopify, or Amazon listing. Get a rewritten title, description, and 13 keyword-targeted tags in ~10 seconds. Free for 5/day, no signup. Pro is $9/month.
ShopScan — on-demand Etsy SEO audit. Pay $19, submit your listing, get a 12-page report (score, keyword gaps, full rewrite, action plan) by email within 24h.
The stack — all free tier
- Cloudflare Workers — API layer, keeps Anthropic key server-side
- Cloudflare KV — rate limiting + Pro token storage
- Cloudflare Pages — static frontend
- Brevo — transactional email (300/day free)
- Stripe Payment Links — no checkout page to build
Total monthly infrastructure cost: $0.
Pro activation without webhooks
Most people implement Stripe webhooks for post-payment activation. I found a simpler pattern.
After payment, Stripe redirects to:
https://contentbase-crw.pages.dev?session_id={CHECKOUT_SESSION_ID}
The frontend POSTs the session_id to /activate-pro on the Worker. The Worker validates the format (cs_live_ prefix — unguessable), generates a token, stores in KV, emails via Brevo.
No webhook endpoint. No signing secret. No HTTPS concerns. Works perfectly.
async function handleActivatePro(request, env) {
const { session_id, email } = await request.json();
if (!session_id?.startsWith('cs_live_')) {
return json({ error: 'Invalid session' }, 400);
}
// Prevent replay attacks
const existing = await env.CB_TOKENS.get(`session:${session_id}`);
if (existing) return json({ token: existing, reused: true });
const token = generateToken();
await env.CB_TOKENS.put(`token:${token}`, 'active');
await env.CB_TOKENS.put(`session:${session_id}`, token);
await sendEmail(env, { to: email, subject: 'Your ContentBase Pro access is live' });
return json({ token, success: true });
}
Rate limiting with Cloudflare KV
No database needed:
async function checkRateLimit(ip, env) {
const key = `rate:${ip}:${new Date().toISOString().split('T')[0]}`;
const count = parseInt(await env.CB_RATE.get(key) || '0');
if (count >= 5) return { allowed: false };
await env.CB_RATE.put(key, String(count + 1), { expirationTtl: 86400 });
return { allowed: true };
}
Keys expire after 24h automatically. Cleanup is free.
What I learned
Cloudflare is absurdly good for this use case. Worker + KV + Pages covers serverless functions, key-value storage, and static hosting — all free, globally distributed.
Zero-friction free tier matters. No email required to use ContentBase. No account. Just paste and get. The conversion to Pro happens after people see the output.
Distribution is harder than building. The technical side took days. Finding actual Etsy sellers to try it is taking weeks. If you've solved Etsy/niche community distribution, I'd genuinely love to hear how.
Live
- ContentBase (free): contentbase-crw.pages.dev
- ShopScan ($19 audit): shopscan-eff.pages.dev
Happy to answer questions about the architecture or the Etsy seller market.
Top comments (0)