← All projects · Project 02
Funnel Asset Kit
An open-source tool that takes one campaign brief and returns a whole funnel: paid ad copy for Meta, TikTok and Google, organic captions, UTM-tagged links, and the metrics actually worth watching at each stage.
The problem
Most ad copy generators hand you five versions of the same sentence, then the same five metrics whatever you are trying to do. That is not how a campaign gets planned, so this one is organised by funnel stage first, platform second.
How it works
Awareness copy is written for curiosity, consideration for proof, conversion for urgency, and each stage reports different KPIs because each is measuring something different. Platform limits are enforced rather than suggested, so a Google Search headline cannot come back at forty characters.
Two decisions that do the real work
1// UTM built with the URL API, not string concatenation, 2// so existing query params and encoding survive 3function buildUtm(baseUrl, stage, platform, slug) { 4 const u = new URL(baseUrl); 5 u.searchParams.set('utm_source', platform.toLowerCase()); 6 u.searchParams.set('utm_medium', 'paid-social'); 7 u.searchParams.set('utm_campaign', slug); 8 u.searchParams.set('utm_content', stage); 9 return u.toString(); 10} 11 12// platform limits are enforced in the system prompt, 13// not left as a polite suggestion 14const systemPrompt = `Respect real platform 15constraints: Google Search headlines max 30 16characters, descriptions max 90. Meta primary text 17under 125 where possible. TikTok copy should sound 18native, not like a repurposed Meta ad. Never invent 19fake statistics. Return ONLY valid JSON.`;
UTMs built with the URL API rather than string concatenation, and platform limits enforced in the prompt rather than suggested. Neither is complicated. Both are the difference between a tool that works and one that mostly works.
What I learned. The real design decision was the information architecture, not the prompt. Grouping by funnel stage rather than by platform is a small structural change that alters what the tool is for. Shipping it three ways forced me to pull the logic apart from the interface, which I had never had to do properly before.