Skip to content
Run this on autopilot — free
Workflow · Audits

Catch Meta Ads Whose Messaging Doesn't Match Their Landing Page

Time to first output: 30-60 minutes to build and configure (Next.js app scaffold + 3 API keys), then a few minutes per analysis run

What it does?

A 5-step pipeline compares what each Meta ad's copy and CTA promise against what the linked landing page actually says, flags every mismatch, and estimates the wasted spend behind it — shown live in a local dashboard.

What you need

  • Meta Ad Account ID (e.g. act_123456789)
  • Anthropic API key (console.anthropic.com)
  • Firecrawl API key (firecrawl.dev)
  • GoMarble API key

First, connect Claude Code and gather your three API keys

This build uses Claude Code to scaffold a Next.js app that pulls Meta Ads data via GoMarble MCP, scrapes landing pages via Firecrawl, and analyzes alignment with the Claude API directly.

1

Connect your Meta Ads account

Go to apps.gomarble.ai, sign up, and connect your Meta Ads account in the Integrations page.

2

Get your GoMarble API key

Click your Profile Picture (top right) → Settings → API Keys → Generate and copy.

3

Add GoMarble MCP to Claude Code

Run the command below in your terminal.

claude mcp add --transport http gomarble https://apps.gomarble.ai/mcp-api/mcp --header "Authorization: Bearer <paste your API key>"
4

Create your .env.local file

In your project root, add three keys: ANTHROPIC_API_KEY (from console.anthropic.com), FIRECRAWL_API_KEY (from firecrawl.dev), and GOMARBLE_API_KEY.

Requires Claude Code installed (npm install -g @anthropic-ai/claude-code) and a Claude account (Pro or Max recommended for higher usage). Works on Mac, Linux, and Windows.

The build prompt

Open Claude Code in your terminal (claude) and paste the entire prompt below — it will scaffold the full Next.js app, install dependencies, and create all files.

Lead-magnet prompt · free

Build a full-stack web application called "Ad ↔ Landing Page Correlation Engine" that detects messaging drift between Meta ads and their landing pages.

Tech Stack
- Frontend: Next.js 14 (App Router) with TypeScript, Tailwind CSS, shadcn/ui
- Backend: Next.js API routes
- AI: Anthropic Claude API (claude-sonnet-4-20250514) via raw fetch (NOT the SDK) for MCP calls
- Meta Ads Data: GoMarble MCP server at https://apps.gomarble.ai/mcp-api/sse
- Landing Page Scraping: Firecrawl API (https://api.firecrawl.dev/v1/scrape) with fallback to basic fetch + cheerio
- State: React state (no database needed)

Environment Variables (.env.local)
ANTHROPIC_API_KEY=<your anthropic key>
FIRECRAWL_API_KEY=<your firecrawl key>
GOMARBLE_API_KEY=<your gomarble key>

Architecture
One page dashboard. User enters Meta Ad Account ID (e.g. act_123456789), clicks "Run Analysis". Backend runs a 5-step pipeline and streams progress via Server-Sent Events.

SSE event format:
data: { "step": 1, "status": "running|done|error", "detail": "...", "data": {...} }

CRITICAL: How to call GoMarble MCP
The Anthropic SDK does NOT support mcp_servers yet. Use raw fetch to the Anthropic API with the beta header:

async function callGoMarbleMCP(prompt: string) {
  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": "2025-01-01",
      "anthropic-beta": "mcp-client-2025-04-04"
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-20250514",
      max_tokens: 4096,
      mcp_servers: [
        {
          type: "url",
          url: "https://apps.gomarble.ai/mcp-api/sse",
          name: "gomarble",
          authorization_token: process.env.GOMARBLE_API_KEY
        }
      ],
      messages: [{ role: "user", content: prompt }]
    })
  });
  return response.json();
}

Use this callGoMarbleMCP function for Step 1 and Step 2. For Step 4-5 (AI analysis with no MCP), you can use the Anthropic SDK normally.

Backend: API Route /api/analyze (POST → SSE stream)
Request body: { accountId: string }

Step 1: Fetch Ad-Level Insights
Call GoMarble MCP with this prompt:

Use the facebook_get_adaccount_insights tool with these EXACT parameters:
- act_id: "${accountId}"
- fields: ["ad_id", "ad_name", "spend", "impressions", "clicks", "ctr", "cpc", "cpm"]
- level: "ad"
- date_preset: "last_30d"
- sort: "spend_descending"
- limit: 20
- filtering: [{"field": "impressions", "operator": "GREATER_THAN", "value": "0"}]
Return the raw data only.

Parse MCP tool results from response.content — look for blocks with type: "mcp_tool_result" and extract ad data.

Step 2: Fetch Creative Details
Take ad_ids from Step 1 (top 15) and call GoMarble MCP:

Use the facebook_get_ad_creative_details tool with:
- ad_ids: ${JSON.stringify(adIds)}
Return ALL creative details including object_story_spec, asset_feed_spec, link URLs, headlines, body text.

Extract:
- Landing page URLs from object_story_spec.link_data.link or asset_feed_spec.link_urls
- Ad copy from object_story_spec.link_data.message, .name (headline), .description
- CTA type

Step 3: Scrape Landing Pages (Firecrawl)
For each unique landing page URL (max 8):

const res = await fetch("https://api.firecrawl.dev/v1/scrape", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${process.env.FIRECRAWL_API_KEY}`
  },
  body: JSON.stringify({
    url,
    formats: ["markdown"],
    onlyMainContent: true,
    waitFor: 3000,
  })
});

Add 1-second delays between requests. Deduplicate URLs (multiple ads may point to same page).

Step 4 & 5: AI Analysis + Scoring
Send all collected data to Claude (SDK is fine here, no MCP needed):

You are an expert performance marketing analyst specializing in ad-to-landing-page alignment audits.

## Ad Data with Creative Copy:
${JSON.stringify(adLPPairs)}

## Scraped Landing Page Content:
${JSON.stringify(scrapedPages)}

For EACH ad-landing page pair, analyze alignment and return a JSON array:
[
  {
    "ad_name": "string",
    "ad_id": "string",
    "spend": "string",
    "impressions": "string",
    "clicks": "string",
    "ctr": "string",
    "landing_page_url": "string",
    "alignment_score": 0-100,
    "severity": "critical|warning|good",
    "mismatches": [
      {
        "type": "offer_mismatch|messaging_drift|cta_mismatch|tone_mismatch|value_prop_gap|urgency_mismatch",
        "ad_says": "exact claim from ad",
        "page_says": "what landing page actually shows",
        "impact": "high|medium|low",
        "explanation": "why this matters"
      }
    ],
    "recommendations": ["specific actionable fix"],
    "wasted_spend_estimate": "estimated $ wasted",
    "overall_assessment": "2-3 sentence summary"
  }
]

CRITICAL: Use ONLY the data provided above. Do NOT fabricate or hallucinate any data. If data is missing, say so explicitly. Every ad_id, URL, and metric must come from the data I provided.

Scoring: 90-100 = perfect alignment, 70-89 = minor drift, 50-69 = significant mismatch, 0-49 = critical.

Focus on: offer consistency, CTA alignment, messaging tone, value prop match, urgency mismatch.

Return ONLY valid JSON. No markdown fences.

Frontend: Dashboard Page (dark theme)
- Header: "Ad ↔ Landing Page Correlation Engine"
- Subtitle: "Detect messaging drift between your Meta ads and landing pages"
- Powered by: GoMarble + Claude AI + Firecrawl
- Input: Text field for Meta Ad Account ID + "Run Analysis" button
- Pipeline Progress: 5 steps with status badges (Waiting → Running → Complete/Failed)
- Summary Cards (3 in a row): Total Ads Analyzed | Average Alignment Score (circular ring) | Critical Issues count
- Results List (sorted worst-first): Each card shows:
  - Score ring (green >80, amber 50-80, red <50)
  - Ad name + severity badge (CRITICAL/WARNING/GOOD)
  - Metrics row (spend, impressions, clicks, CTR)
  - Landing page URL (clickable)
  - Overall assessment
  - Mismatches: type, "Ad says" vs "Page says", impact badge
  - Recommendations with arrow bullets

SSE Implementation
Backend streams progress. Frontend consumes via fetch + ReadableStream.

File Structure
ad-lp-engine/
├── app/
│   ├── page.tsx
│   ├── layout.tsx
│   ├── globals.css
│   └── api/analyze/route.ts
├── components/
│   ├── ScoreRing.tsx
│   ├── PipelineProgress.tsx
│   ├── ResultCard.tsx
│   └── SummaryCards.tsx
├── lib/
│   ├── types.ts
│   ├── gomarble.ts
│   ├── scraper.ts
│   └── analyzer.ts
├── .env.local
└── package.json

Build this app. Start with npx create-next-app@latest ad-lp-engine --typescript --tailwind --app --src=no. Install: @anthropic-ai/sdk, cheerio. Initialize shadcn with npx shadcn@latest init.

IMPORTANT: Make sure .env.local values are loaded correctly. Use process.env.ANTHROPIC_API_KEY directly — do NOT let ~/.zshrc or shell exports override them. Explicitly read from .env.local if needed.

What you get back

  • Format: A local Next.js dashboard (localhost:3000) that streams a 5-step pipeline via SSE and ranks every ad-to-landing-page pair. Each pair shows:
    • Alignment score (0-100)
    • Mismatch type (offer / messaging / CTA / tone / value-prop / urgency)
    • Estimated wasted spend
    • Fix recommendation
Upgrade

Want this automated?

Run the prompt above every Monday morning automatically. GoMarble Agents don't just deliver the report (Slack / email / in-app) — they can execute the recommended changes directly in your ad account, too. Offload the whole recurring task and stop doing it manually.

Try GoMarble Agents free →

FAQ

Does this ever change my Meta ads or landing pages?
No — the only GoMarble tools called are read-only (facebook_get_adaccount_insights, facebook_get_ad_creative_details), plus a Firecrawl scrape of the landing page. The app only produces a report.
What operating systems does this run on?
The Important Notes section states it works on Mac, Linux, and Windows.
How many ads does one run analyze?
Up to the top 20 ads by spend over the last 30 days, deduplicated down to a max of 8 unique landing pages.
What if I don't want to build this myself?
GoMarble already does ad-to-landing-page analysis, creative fatigue detection, and full performance reporting with no code, at apps.gomarble.ai.
Which AI model does the build use?
claude-sonnet-4-20250514, called via raw fetch to the Anthropic Messages API with the mcp-client-2025-04-04 beta header — the spec notes the Anthropic SDK doesn't support mcp_servers yet.
Do I need a database?
No — the spec explicitly says state is kept in React state, no database needed.

Skip the prompt — let GoMarble do this for you.

Sign up, connect your ad accounts, and ad ↔ page sync audit engine runs on every account, every week, automatically.