How I Built a Self-Feeding SEO Engine with GPT-4o Vision + Next.js 15

Two weeks ago, I launched an ai tattoo generator called TattooRed. Today, I have 200 pages generated and 15 indexed by Google. But here’s the interesting part: users generate the content, GPT-4o Vision enriches it, and Next.js 15 serves it—automatically.

The architecture is designed to scale from 0 to 100K+ pages at $0.006 per page. Here’s exactly how it works—including the disasters I didn’t anticipate.

🎯 The Problem: 135K Monthly Searches I Couldn’t Cover Manually

I started building an ai tattoo generator. The obvious keyword was “ai tattoo generator” (22K monthly searches). But then I discovered “tattoo ideas” gets 135K monthly searches with similar difficulty (56% vs 50%).

The opportunity was massive. But here’s the challenge:

How do you create 10,000+ unique, SEO-optimized pages for long-tail keywords like:

  • “minimalist lion tattoo ideas”
  • “watercolor phoenix back tattoo”
  • “geometric dragon sleeve for men”
  • “small butterfly ankle tattoo for women”

Manual content creation? Impossible. Hiring writers? $50-100 per article = $500K+ for 10K pages.

The solution: Turn user creativity into SEO content automatically.

🏗️ The Architecture: User Content → AI Analysis → SEO Pages

Here’s how the system works:

1. User Generates a Tattoo

Users describe their tattoo idea (e.g., “phoenix rising from ashes on my back”). The system:

  • Sends the prompt to ModelsLab’s Flux API
  • Generates a professional tattoo design (white background, no body parts)
  • Returns the image in ~15 seconds

Cost: $0.0047 per image

2. Auto-Publish Flow (Free Users)

Free users get their tattoos published automatically to the tattoo ideas gallery. This is the exchange: free generation in return for SEO content contribution.

When published, the system:

  • Uploads image to Supabase Storage
  • Sends image + user prompt to GPT-4o-mini Vision
  • Receives structured SEO content back
  • Creates a new Next.js page automatically

3. GPT-4o Vision Analyzes & Generates Content

This is where the magic happens. Here’s a simplified version of the API call:

// lib/openai-seo-generator.ts
export async function analyzeTattooAndGenerateSEO(
  imageUrl: string, 
  userPrompt: string,
  existingCategories: string[]
) {
  const response = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [
      {
        role: "system",
        content: `You are an expert tattoo analyst and SEO content writer.`
      },
      {
        role: "user",
        content: [
          { 
            type: "text", 
            text: `User prompt: "${userPrompt}"

            Return JSON with SEO-optimized content including:
            title, meta description, 500+ word analysis, categories, etc.`
          },
          { 
            type: "image_url", 
            image_url: { url: imageUrl } 
          }
        ]
      }
    ],
    response_format: { type: "json_object" }
  });

  return JSON.parse(response.choices[0].message.content);
}

Cost: $0.0015 per analysis (GPT-4o-mini Vision is 10x cheaper than GPT-4o)

4. Next.js 15 Creates Pages Automatically

The returned data creates a new page at /tattoo-ideas/[slug]:

// app/tattoo-ideas/[slug]/page.tsx
export async function generateMetadata({ params }: Props) {
  const tattoo = await getTattooBySlug(params.slug);

  return {
    title: tattoo.seo_title,
    description: tattoo.seo_description,
    openGraph: {
      title: tattoo.seo_title,
      images: [tattoo.image_url],
    },
  };
}

// ISR: Revalidate every hour
export const revalidate = 3600;

💡 Side note: I built this with Claude Code as my coding assistant. The architecture decisions are mine, but Claude helped me write cleaner TypeScript and avoid Next.js pitfalls.

5. Multi-Category Magic

Each tattoo automatically appears in multiple category pages. A “phoenix rising back tattoo” shows up in:

  • /tattoo-ideas/category/animals
  • /tattoo-ideas/category/birds
  • /tattoo-ideas/category/mythology
  • /tattoo-ideas/category/unisex/animals (combined)

One user generation = 5-10 SEO entry points. This is the multiplier effect.

💰 The Economics: Infinite Scale at $0.006 Per Page

Let’s break down the cost per generated SEO page:

Image generation (Flux):        $0.0047
GPT-4o-mini Vision analysis:    $0.0015
Supabase storage:               $0.0001
-----------------------------------------
Total per page:                 $0.0063

At scale:

  • 1,000 pages = $6.30
  • 10,000 pages = $63
  • 100,000 pages = $630

Compare to traditional content:

  • Freelance writers: $50-100/article
  • Content agencies: $200+/article
  • 10,000 articles = $500K – $2M

ROI calculation:
If I get 100 paying users at $13.95/month = $1,395 MRR, that covers 221,000 generated pages. The economics work at any scale.

😱 The “Oh Shit” Moment (aka What Could Go Wrong)

So there I was, 2 AM, super proud of my creation. System running smoothly. Users generating tattoos. SEO content flowing like a river.

I went to bed feeling like a genius.

Then, 10 minutes later, lying in the dark, the thoughts started:

“Wait… what if OpenAI’s API goes down?”

“What if I run out of credits and don’t notice?”

“What if the background process fails silently and I have 1,000 orphaned tattoos with no SEO content?”

I opened my laptop. Checked the database.

Yep. 37 orphaned tattoos. Published images, but the GPT-4o enrichment process had failed silently. No SEO content. No categories. Just… floating in the void.

The Problem: Silent Failures

Here’s what was happening:

  1. User generates tattoo ✅
  2. Image uploads to Supabase ✅
  3. Tattoo appears in gallery ✅
  4. Background job triggers to generate SEO content… ❌ (fails silently)

Why it failed:
At first, I blamed the usual suspects:

  • OpenAI API timeout
  • Rate limits
  • Network hiccups
  • Low credits
  • A process crash

But the real issue was something different.
Everything worked perfectly locally… but failed silently once deployed on Vercel.

Locally, my enrichment function ran synchronously:
I sent the GPT-4o-mini Vision request → waited for the response → stored the SEO content.
No queue, no background jobs, no race conditions.

But on Vercel, the story changed:

  • Vercel serverless functions have strict execution time limits
  • After a few seconds, the function gets hard-killed
  • No error is thrown back into your app
  • No logs unless you dig deep

The tattoo gets created… but the enrichment never finishes

This leads to the weirdest bug:
Everything looks successful from the user’s perspective, but the SEO content is missing.

I also tried a “fire-and-forget” strategy (trigger enrichment and return immediately), but serverless environments don’t guarantee the background execution will complete—so enrichment jobs were still randomly failing.

In other words:

👉 My code wasn’t the problem — the serverless runtime model was.

The tattoos existed, but they were SEO zombies—alive but without the content that makes them discoverable.

The Solution: The “Orphan Tattoo Recovery System”

I built an admin panel with a simple but powerful feature:

“Check for Orphan Tattoos” button

Here’s what it does:

// app/api/admin/pending-tattoos/route.ts (simplified)

export async function GET() {
  // Find tattoos that are published but missing SEO content
  const orphanTattoos = await supabase
    .from('tattoos')
    .select('*')
    .is('seo_content', null) // No SEO content yet
    .eq('published', true)   // But already published
    .order('created_at', { ascending: false });

  return Response.json({ 
    orphans: orphanTattoos.data,
    count: orphanTattoos.data?.length 
  });
}

export async function POST(request: Request) {
  const { tattooIds } = await request.json();

  // Process orphans one by one
  const results = [];
  for (const id of tattooIds) {
    try {
      const tattoo = await getTattooById(id);

      // Retry SEO generation
      const seoContent = await analyzeTattooAndGenerateSEO(
        tattoo.image_url,
        tattoo.user_prompt,
        existingCategories
      );

      // Update tattoo with SEO content
      await supabase
        .from('tattoos')
        .update({
          seo_title: seoContent.title,
          seo_description: seoContent.meta_description,
          content: seoContent.content,
          // ... other fields
        })
        .eq('id', id);

      results.push({ id, status: 'success' });

    } catch (error) {
      results.push({ id, status: 'failed', error: error.message });
    }
  }

  return Response.json({ processed: results });
}

In the admin panel:

Orphan Tattoos Detected: 37

[Check for Orphans] 

┌─────────────────────────────────────────┐
│ phoenix-back-a1b2c3                    │
│ Created: 2 hours ago                   │
│ Status: Missing SEO content            │
│ [Process Now]                          │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│ dragon-sleeve-d4e5f6                   │
│ Created: 5 hours ago                   │
│ Status: Missing SEO content            │
│ [Process Now]                          │
└─────────────────────────────────────────┘

[Process All (37 tattoos)]

Click the button. Boom. All 37 orphans get their SEO content in ~2 minutes.

Why this works:

  • ✅ Manual recovery when automation fails
  • ✅ Retry logic for failed API calls
  • ✅ Visual confirmation that everything is caught up
  • ✅ Peace of mind (I can sleep now)

Bonus feature I added:
Daily cron job that checks for orphans automatically and sends me a notification:

🚨 Found 12 orphan tattoos from the last 24 hours
👉 Check admin panel: tattoored.com/admin/tattoos

📊 Early Results & Lessons Learned (2 Weeks In)

Current status:

  • ✅ 200 pages generated
  • ✅ 15 pages indexed by Google
  • ✅ Average content length: 520 words
  • ✅ Generation time: <15 seconds per page
  • ✅ Zero orphaned tattoos (thanks to recovery system)

What’s working:

  1. User prompts are natural long-tail keywords

    • User: “minimalist geometric lion with sunset background”
    • Auto-targets: “minimalist lion tattoo”, “geometric lion”, “sunset tattoo ideas”
    • No keyword research needed—users do it for me
  2. GPT-4o-mini Vision quality is excellent

    • 90% of content needs zero editing
    • Understands tattoo culture (placement, style, symbolism)
    • 10x cheaper than GPT-4o ($0.0015 vs $0.015)
  3. The orphan recovery system is essential

    • Caught 37 failures in the first week
    • Now runs as daily cron + manual check
    • Converts “oh shit” moments into “handled”

What I’m still figuring out:

  1. Indexing speed varies wildly

    • Some pages indexed in 24h, others take 7+ days
    • Testing XML sitemap optimization
  2. Category page optimization

    • Auto-generated intro content needs improvement
    • Testing different layouts for gallery grids

🚀 What’s Next: Scaling to 10K Pages

Short-term (next 30 days):

  • Reach 1,000 generated pages
  • Target 100+ indexed pages
  • Track first keyword rankings

Mid-term (3 months):

  • Scale to 10,000 pages
  • Monitor conversion: organic traffic → free users → paid users
  • Add A/B testing for content formats

Long-term (6+ months):

  • 50K+ pages (depending on user growth)
  • Multi-language support (Spanish, Portuguese, French)
  • Artist marketplace integration

🏗️ Building in Public: BoomPath + TattooRed

I’m documenting this entire journey on Twitter (@PaulR_o_w) as part of my #buildinpublic and #rankinpublic experiment.

Here’s the meta part that makes this interesting: I built BoomPath, an AI-powered SEO platform that goes beyond basic automation. BoomPath:

  • Analyzes your business to understand what you actually do
  • Finds strategic keywords (not just volume—intent and competition)
  • Monitors your competitors (what’s working for them)
  • Writes SEO-optimized content tailored to your niche
  • Builds backlinks automatically through directory submissions and strategic outreach

It’s not just another SurfSEO or AiSEO clone—it’s the entire SEO workflow, automated.

And now I’m using BoomPath to rank TattooRed. So the stack is:

BoomPath (my SEO platform)
    ↓
TattooRed (AI tattoo generator)
    ↓
User-generated content
    ↓
GPT-4o enrichment
    ↓
Automatic SEO pages
    ↓
Rankings (tracked publicly on Twitter)

It’s turtles all the way down. 🐢

The beautiful irony? I’m proving BoomPath works by using it on TattooRed, and documenting both journeys publicly. If you want to follow the day-to-day wins, fails, and metrics, I’m posting regular updates on X.

🛠️ The Tech Stack

Core infrastructure:

  • Next.js 15 (App Router + Server Components)
  • Supabase (PostgreSQL + Auth + Storage)
  • Vercel (hosting + ISR)

AI services:

  • GPT-4o-mini Vision (content generation)
  • ModelsLab Flux (tattoo image generation)

SEO:

  • BoomPath (keyword research, competitor analysis, content strategy, backlink building)
  • Automated sitemap generation
  • Internal linking automation

Development tools:

  • Claude Code (coding assistant)
  • TypeScript
  • Tailwind CSS

🎓 Key Takeaways for Builders

If you’re considering programmatic SEO with AI:

  1. User-generated content is gold

    • Let users create the initial input
    • AI enriches it into SEO-ready pages
    • Everyone wins: users get free value, you get content
  2. GPT-4o-mini Vision is underrated

    • 90% of GPT-4o quality at 10% the cost
    • Perfect for high-volume content generation
  3. Build recovery systems from day one

    • Background jobs WILL fail
    • Silent failures are the worst
    • Manual recovery buttons save your sanity
  4. Many-to-many category relations scale

    • One piece of content → multiple entry points
    • Automatic internal linking
    • SEO multiplier effect
  5. Economics matter more than tech

    • $0.006 per page = infinite runway
    • Focus on user acquisition, not content costs
  6. Use your own products

    • Building BoomPath forced me to understand SEO deeply
    • Using it on TattooRed proves it works
    • Public accountability creates urgency

📝 Meta: How This Article Was Written

Full transparency: I wrote this article with Claude’s help.

My role:

  • Architecture decisions and implementation
  • Real-world disasters and solutions (orphan tattoos, API failures)
  • Metrics and learnings
  • Business strategy

Claude’s role:

  • Article structure and flow
  • Technical explanation clarity
  • Editing for dev.to audience

The result: This article in 2 hours instead of 8-10 hours. That’s AI as a thinking partner.

💬 Let’s Discuss

I’m curious about your experiences:

  • Have you built programmatic SEO systems?
  • What’s your backup plan for AI API failures?
  • How do you handle silent background job failures?
  • Ever had an “oh shit” moment at 2 AM?

Drop your thoughts in the comments below. I’ll reply to everyone.

Follow my build-in-public journey: Twitter @PaulR_o_wTattooRed.com 🔥

Similar Posts