CampaignOS
AI-Native Multi-Tenant Marketing Platform — Complete Technical Specification
Executive Summary
CampaignOS converts a website URL and advertising budget into a fully planned, copy-written, multi-platform ad campaign — and publishes it with explicit user consent via MCP connectors. Enter a URL and a budget. Get a complete, publishable campaign in under 5 minutes.
Core Capabilities
| Capability | Description | AI Layer |
|---|---|---|
| Brand Intelligence | Scrapes any URL; extracts design tokens, tone, colours, audience signals | Claude Vision |
| Persona Engine | 3–5 personas with platform affinity, messaging hooks, and budget splits | Claude API |
| Campaign Generator | Per-persona × per-platform: headline, copy, CTA, targeting params, KPIs | Claude API |
| Copy Variant Engine | 3 variants per campaign: Direct, Curiosity, Social Proof + live ad previews | Claude API |
| MCP Connectors | Publishes to Google Ads, Meta, LinkedIn, X via OAuth. Consent-gated. | MCP Server |
| Multi-tenant Core | Full workspace isolation per agency/brand. RBAC: Owner / Manager / Viewer | Postgres RLS |
| Live Analytics | Unified performance dashboard. Budget pacing alerts. | Webhooks |
Key Metrics
| Platforms | Avg Setup Time | Campaign Types | MCP Tools |
|---|---|---|---|
| 6 | 4 minutes | 18 | 14 |
User Flow
Intake 30 seconds
Enter website URL, set monthly budget ($500–$50K), select target ad platforms.
Brand Analysis Claude Vision
Platform scrapes the URL and extracts industry, tone, brand colours, audience, USP, and keywords. Results stream live to the UI.
Persona Review Editable
4 AI-generated personas with messaging hooks and budget % splits. Toggle personas in/out or regenerate any individual one.
Campaign Generation AI Copy
Per-persona × per-platform campaigns: headline, body copy, CTA, targeting params, estimated CTR/CPC/reach.
Creatives + Preview 3 variants
Direct / Curiosity / Social Proof copy variants with live platform-accurate ad previews for Google, Meta, LinkedIn, and X.
Publish + Track Consent-gated
OAuth connect → Preview → Explicit "Authorize & Publish" → MCP tool call → Audit log entry → Live performance tracking.
UX Principles
- Transparency first — Always show what the AI extracted. Never black-box a step.
- Editability at every level — Personas, copy, budget splits, targeting are all editable inline.
- Granular regeneration — Regenerate at any level: this persona, this platform, this copy variant.
- Consent is explicit, never implied — OAuth connect and publish are two separate clicks, always.
- Draft before spend — Campaigns land as drafts on ad platforms. No money moves until the user confirms.
Architecture Approach Comparison
Decision Matrix
| Criterion | Claude MCP | LangGraph | Vercel AI | n8n / Make |
|---|---|---|---|---|
| Multi-tenant isolation | ✅ Native RLS | ✅ Custom | ⚠️ Partial | ❌ Manual |
| AI reasoning depth | ✅ Full chain | ✅ Full chain | ⚠️ Medium | ❌ Shallow |
| Ad platform connectors | ✅ via MCP | ✅ via SDK | ⚠️ via SDK | ✅ Built-in |
| Background job support | ✅ BullMQ | ✅ Queue | ❌ Limited | ✅ Built-in |
| White-label ready | ✅ | ✅ | ⚠️ | ❌ |
| Consent / audit layer | ✅ Native | ✅ Custom | ⚠️ | ❌ |
| Time to MVP | 3–4 weeks | 4–6 weeks | 1–2 weeks | 1 week |
| Monthly infra cost | $80–$200 | $100–$300 | $50–$150 | $200–$500 |
| Vendor lock-in | Low | Low | Medium | High |
| IP ownership | Full | Full | Full | Partial |
Build vs Buy Analysis
14-Week Build Roadmap
| Phase | Timeline | Deliverables |
|---|---|---|
| Phase 1 — Core AI + Intake | Wk 1–3 | Brand scraper (Puppeteer + Claude Vision), Persona generator, Campaign planner, Copy variant engine, Basic Next.js UI |
| Phase 2 — Multi-tenant + Auth | Wk 4–5 | NextAuth + workspace isolation, Postgres RLS policies, RBAC (Owner / Manager / Viewer), Client management UI |
| Phase 3 — MCP Connectors | Wk 6–8 | MCP Server setup, Google Ads OAuth + draft creation, Meta Marketing API, LinkedIn Ads API |
| Phase 4 — Publish + Analytics | Wk 9–11 | Consent-gate publish flow, Performance pull-back, Budget pacing alerts, Unified analytics dashboard |
| Phase 5 — Polish + Scale | Wk 12–14 | White-label theming, API product layer, Monitoring + alerting, Documentation |
Cost Breakdown
| Line Item | Estimated Cost |
|---|---|
| Developer time (1 FT × 14 weeks) | $28,000 – $42,000 |
| Claude API (dev + staging) | $200 – $400 |
| Infra (Vercel + Supabase + Redis) | $150 – $300 |
| Ad platform dev accounts | $0 (free tiers) |
| Total Build Investment | $29,000 – $43,000 |
| Monthly Running Cost | $300 – $600 / month |
Buy Landscape
| Tool | Category | Price / mo | What It Covers | Critical Gap |
|---|---|---|---|---|
| Jasper | AI Copy | $49–$125 | AI copy generation | No ad platform publishing |
| AdCreative.ai | AI Copy | $29–$149 | Ad creative generation | No persona engine or planning |
| Smartly.io | AI Copy | Custom | Ad automation + publishing | No AI brand analysis, very expensive |
| n8n Cloud | Automation | $20–$50 | Workflow + connectors | No AI reasoning layer, DIY everything |
| Make | Automation | $9–$29 | Visual workflows | Shallow AI, no multi-tenant |
| HubSpot Mktg Hub | Full-stack | $800–$3,200 | Full marketing suite | Generic, not AI-native |
| Salesforce Mktg Cloud | Full-stack | Custom | Enterprise campaigns | 18-month impl, $100K+ contracts |
| Albert.ai | Full-stack | Custom | AI ad management | Black-box AI, no brand analysis |
System Architecture
Six-Layer Stack
MCP Tool Definitions
| Tool Name | Input Schema | Description |
|---|---|---|
analyze_website | url, depth | Puppeteer scrape + Claude Vision: extracts brand tokens, tone, palette, audience signals |
generate_personas | brand_analysis, budget, platforms[] | Produces 3–5 personas with platform affinity, budget split, messaging hook |
plan_campaign | personas[], budget, platforms[] | Per-persona × per-platform campaign: headline, copy, CTA, targeting, KPIs |
generate_ad_copy | campaign_id, platform, persona | Writes 3 copy variants: Direct / Curiosity / Social Proof |
create_ad_draft | campaign_id, platform | Creates draft on ad platform via SDK. No spend committed. Returns draft_id. |
publish_campaign | campaign_id, platform, consent | Publishes approved draft. require_consent: true by default. Writes audit record. |
get_performance | campaign_id, date_range | Pulls impressions, clicks, spend, conversions. Returns unified schema. |
pause_campaign | campaign_id, platform | Pauses live campaign. Requires user confirmation. |
Multi-tenant Data Model
-- Workspace hierarchy workspaces (id uuid PK, name, slug, plan, created_at) users (id, workspace_id FK, role, email, oauth_tokens_enc) brands (id, workspace_id FK, url, brand_snapshot jsonb) personas (id, brand_id FK, name, traits jsonb, platform_affinity jsonb, budget_pct) campaigns (id, brand_id FK, status, budget, platform, flight_start, flight_end) ad_drafts (id, campaign_id FK, variant, copy jsonb, targeting jsonb, consent_at) performance (id, campaign_id FK, date, impressions, clicks, spend, conversions) audit_log (id, workspace_id, user_id, action, resource_id, metadata jsonb) -- Row Level Security enforced at DB layer CREATE POLICY workspace_isolation ON campaigns USING (workspace_id = current_setting('app.workspace_id')::uuid);
RBAC Permissions
| Action | Owner | Manager | Viewer |
|---|---|---|---|
| Create workspace / invite users | ✅ | ❌ | ❌ |
| Analyze brand | ✅ | ✅ | ❌ |
| Generate personas & campaigns | ✅ | ✅ | ❌ |
| Generate ad copy | ✅ | ✅ | ❌ |
| Publish campaign | ✅ | ✅ | ❌ |
| View campaigns & analytics | ✅ | ✅ | ✅ |
| Manage billing | ✅ | ❌ | ❌ |
Campaign Generation — Deep Dive
The Four Claude Prompts
Prompt 1 — Brand Analysis
You are a brand strategist AI. When given a website URL/domain, infer likely brand characteristics. Respond ONLY with a valid JSON object — no markdown, no backticks, no explanation. Shape: { "industry": "...", "tone": "...", "colors": ["#hex1", "#hex2"], "audience": "...", "usp": "...", "keywords": ["k1", "k2", "k3"] }
Prompt 2 — Persona Generation
You are an audience strategy expert. Respond ONLY with a JSON array. Generate 4 personas with this shape: [{ "name": "...", "age": "25–35", "role": "...", "platforms": ["..."], "budgetPct": 25, // must sum to 100 "painPoint": "...", "messagingHook": "...", "icon": "◈" // one of: ◈ ⬡ ◇ △ }]
Prompt 3 — Campaign Planning
You are a performance marketing strategist. Respond ONLY with a JSON array. One item per persona×platform combination: [{ "persona": "...", "platform": "...", "format": "...", "monthlyBudget": 500, "headline": "...", // max 40 chars "primaryCopy": "...", // max 90 chars "cta": "...", // max 20 chars "targeting": { "age": "...", "interests": ["..."] }, "kpis": { "ctr": "2.1%", "cpc": "$1.20", "reach": "45K" } }]
Prompt 4 — Copy Variant Writing
You are a world-class copywriter. Respond ONLY with a JSON object. { "variants": [ { "label": "Direct", "headline": "...", "body": "...", "cta": "..." }, { "label": "Curiosity", "headline": "...", "body": "...", "cta": "..." }, { "label": "Social Proof", "headline": "...", "body": "...", "cta": "..." } ] } Variants must be meaningfully different in angle and approach. Headlines: max 40 chars. Body: max 90 chars. CTA: max 20 chars.
Copy Variant Strategy
| Variant | Angle | Best For | Example Hook |
|---|---|---|---|
| Direct | States the benefit plainly | Bottom-funnel, high-intent | "Cut campaign setup from days to minutes" |
| Curiosity | Opens a loop or asks a question | Top-funnel, cold audiences | "What if your next campaign wrote itself?" |
| Social Proof | Leverages numbers or trust signals | Mid-funnel, consideration | "10,000+ marketers already use this" |
Platform Ad Format Specs
| Platform | Format | Headline Limit | Body Limit | CTA Options |
|---|---|---|---|---|
| Google Search | Text ad | 30 chars × 3 | 90 chars × 2 | Custom |
| Meta Feed | Single image / carousel | 40 chars | 125 chars | 20 options |
| Sponsored Content | 70 chars | 150 chars | 18 options | |
| X / Twitter | Promoted Post | 70 chars | 280 chars | Custom |
| TikTok | In-feed video | 80 chars | N/A | 10 options |
Tech Stack
| Concern | Choice | Rationale |
|---|---|---|
| Frontend | Next.js 14 + Tailwind | App Router, server components, streaming, edge-ready |
| AI Orchestration | Claude MCP | Native tool calling, streaming, multi-step reasoning |
| Website Scraping | Puppeteer + Claude Vision | Screenshot + structured extraction in one pass |
| Background Jobs | BullMQ + Redis | Reliable async queue for long-running AI jobs |
| Authentication | NextAuth.js | Session management + per-platform OAuth 2.0 |
| Database | Supabase + RLS | Row-level security for multi-tenant isolation |
| Ad: Google Ads | google-ads-api | Official Node.js SDK, wraps gRPC API |
| Ad: Meta | meta-ads-sdk | Official Marketing API client |
| Ad: LinkedIn | linkedin-api-client | LinkedIn Marketing API v2 |
| Monitoring | Sentry + Datadog | Error tracking + APM |
| Deployment | Vercel + Railway | Zero-config deploys, auto-scaling |
Deployment Guide
Environment Variables
# Claude API ANTHROPIC_API_KEY=sk-ant-... # Supabase NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ... SUPABASE_SERVICE_ROLE_KEY=eyJ... # Auth NEXTAUTH_SECRET=your-secret-here NEXTAUTH_URL=https://yourdomain.com # Redis REDIS_URL=redis://... # Ad Platform OAuth GOOGLE_ADS_CLIENT_ID=... GOOGLE_ADS_CLIENT_SECRET=... META_APP_ID=... META_APP_SECRET=... LINKEDIN_CLIENT_ID=... LINKEDIN_CLIENT_SECRET=...
Claude API Proxy Route (Required)
import { NextRequest, NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { ratelimit } from '@/lib/redis'; export async function POST(req: NextRequest) { // 1. Auth check const session = await getServerSession(authOptions); if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); // 2. Rate limit per workspace const { success } = await ratelimit.limit(session.user.workspaceId); if (!success) return NextResponse.json({ error: 'Rate limited' }, { status: 429 }); // 3. Proxy with server-side key — key never touches the browser const body = await req.json(); const response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.ANTHROPIC_API_KEY!, 'anthropic-version': '2023-06-01', }, body: JSON.stringify(body), }); return NextResponse.json(await response.json()); }
Vercel Deployment
npm i -g vercel
vercel deploy
vercel env add ANTHROPIC_API_KEY
vercel env add NEXT_PUBLIC_SUPABASE_URL
# add remaining env vars, then promote
vercel --prod
MCP Server Implementation
Publish Tool — Consent Gate Pattern
export const publishCampaign = { handler: async (args) => { // 1. Consent record MUST exist before any publish action const consent = await db.query( `SELECT * FROM audit_log WHERE resource_id = $1 AND action = 'consent_given' ORDER BY created_at DESC LIMIT 1`, [args.campaign_id] ); if (!consent.rows.length) { return { error: 'CONSENT_REQUIRED', message: 'User must explicitly authorize before publishing.' }; } // 2. Publish via platform SDK (not raw API call) const draft = await db.getApprovedDraft(args.campaign_id); const result = await platformSDK[args.platform].publishDraft(draft.platform_draft_id); // 3. Write immutable audit record await db.query( `INSERT INTO audit_log (workspace_id, action, resource_id, metadata) VALUES ($1, 'campaign_published', $2, $3)`, [args.workspace_id, args.campaign_id, { platform: args.platform, result }] ); return { success: true, platform_campaign_id: result.id, status: 'live' }; } };
Security & Compliance
| Area | Mechanism | Detail |
|---|---|---|
| Tenant isolation | Postgres RLS | workspace_id scoping at DB layer — app bugs cannot leak cross-tenant data |
| Session auth | NextAuth | Workspace membership validated on every API request |
| OAuth token storage | AES-256 encryption | Tokens encrypted at rest, per-workspace key |
| Consent gate | Audit log check | publish_campaign tool verifies consent record exists before any API call |
| Audit log | Append-only table | Users cannot delete or modify consent/publish records |
| OAuth scopes | Minimum privilege | Request ads:write, never account:admin |
| API key security | Server-side proxy | Claude API key never exposed in client-side code |
| Rate limiting | Upstash Redis | Per-workspace request limits on /api/claude proxy |
| Data retention | Auto-purge policy | Screenshots purged after 30 days; PII never stored on CampaignOS |
| Compliance | SOC 2 Type II path | Achievable by Phase 5 via Supabase compliance tooling |
Risks & Mitigations
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Ad platform API breaking changes | Medium | High | SDK abstraction layer; pin versions; monitor changelogs |
| Claude API latency on large brand analysis | Medium | Medium | Async job queue; streaming progress to UI |
| MCP ecosystem immaturity | Low | Medium | Wrap MCP tools with fallback REST calls |
| Multi-tenant data leak via app bug | Low | High | RLS enforced at DB layer; pen test before launch |
| OAuth token expiry causing publish failures | High | Low | Proactive token refresh; retry queue with alerts |
| Claude API cost overrun at scale | Medium | Medium | Cache brand analyses 7 days; batch persona generation |
| Agency client ad overspend | Low | High | Hard budget caps in draft creation; daily spend alerts |
| Wrong brand analysis for unknown domain | Medium | Medium | Allow full manual override at every step |
Next Steps
| Phase | Timeline | Actions |
|---|---|---|
| Immediate | Week 1 | Scaffold Next.js + Supabase + RLS. Implement analyze_website MCP tool. Build intake form with streaming brand analysis. Set up /api/claude proxy with auth + rate limiting. |
| Short-term | Wk 2–5 | Complete persona + campaign + copy variant MCP tools. Add workspace management and RBAC. Build strategy review UI with live ad previews. |
| Medium-term | Wk 6–11 | Integrate Google Ads and Meta SDKs as MCP connectors. Implement consent-gated publish flow with audit log. Build unified analytics dashboard. |
| Launch | Wk 12–14 | White-label theming. API product surface. Security audit and penetration test. Documentation and onboarding flows. |
Appendix
Glossary
| Term | Definition |
|---|---|
| MCP | Model Context Protocol — Anthropic's open protocol for connecting AI models to external tools and data sources |
| RLS | Row Level Security — Postgres feature enforcing data access at the database layer, not the application layer |
| RBAC | Role-Based Access Control — permissions determined by user role (Owner / Manager / Viewer) |
| Ad Draft | A campaign staged on the ad platform with no spend committed — for review before publish |
| Consent Gate | A mandatory user confirmation step before any action that incurs real ad spend |
| Persona | AI-generated audience segment with demographic, psychographic, and platform affinity data |
| Copy Variant | One of three ad copy versions (Direct / Curiosity / Social Proof) for the same campaign |
| Workspace | A multi-tenant isolation unit — one workspace per agency or brand client |
Supported Ad Platforms (v1.0)
| Platform | API | Auth | Draft | Performance Pull |
|---|---|---|---|---|
| Google Ads | Google Ads API v16 | OAuth 2.0 | ✅ | ✅ |
| Meta (FB / IG) | Meta Marketing API v19 | OAuth 2.0 | ✅ | ✅ |
| LinkedIn Marketing API v2 | OAuth 2.0 | ✅ | ✅ | |
| X (Twitter) | X Ads API v12 | OAuth 1.0a / 2.0 | ✅ | ✅ |
| TikTok | TikTok for Business API | OAuth 2.0 | Roadmap | Roadmap |
Reference Links
- Anthropic MCP Docs: https://modelcontextprotocol.io
- Claude API Reference: https://docs.anthropic.com
- Supabase RLS Guide: https://supabase.com/docs/guides/auth/row-level-security
- Google Ads API: https://developers.google.com/google-ads/api/docs/start
- Meta Marketing API: https://developers.facebook.com/docs/marketing-apis
- LinkedIn Marketing API: https://learn.microsoft.com/en-us/linkedin/marketing/
- NextAuth.js: https://next-auth.js.org
- BullMQ: https://docs.bullmq.io