◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-04-20Intermediate

Integrating Claude API into a Wallpaper App — A Full Implementation Record

From someone who's been building wallpaper and healing apps since 2014, here's a complete record of how I integrated Claude API for content curation, multilingual App Store copy generation, and auto-tagging — with full working code.

Claude API128indie development25app development3wallpaper appmultilingual4content curationAPI implementation

✦ Premium Article

I've been building iOS and Android wallpaper and healing apps independently since 2014, and today I run several of them. One of the reasons I've been able to keep going in this space is that I've consistently faced the challenge of maintaining both the volume and quality of content.

Integrating Claude API into my workflow came from that same place. My goal wasn't "generate wallpapers with AI" — it was "handle the large amount of content I already have more intelligently."

This article documents three implementation patterns I actually use, with code. If you work with image content as an indie developer, I think you'll find something useful here.

Why I Chose Claude API

The core problem I'd been managing manually: metadata for a large image library. Category classification, description writing, tag assignment, localization — all of this done by hand was eating up hours every week.

Image generation AI could have automated the content itself, but the whole point of my apps is a curated aesthetic and worldview. I wasn't willing to hand that off. What I needed was a way to organize and describe existing content more intelligently.

Claude stood out for a few reasons: solid Japanese language support, the ability to make consistent judgments over long contexts, and — this matters a lot in the healing app space — tone instructions that actually work. When I say "keep it gentle and calm," the output actually reflects that. That's not a given across all models.

Implementation 1: Content Curation Scoring

The first thing I built was a curation scoring system for new wallpaper images being added to the library.

Rather than passing the image itself to Claude, I pass human-written text notes about each image (color palette, motif, shooting conditions, mood) and ask Claude to evaluate how well it fits the app concept.

import anthropic
import json
 
client = anthropic.Anthropic()
 
CURATION_SYSTEM_PROMPT = """
You are a content curator for a healing and minimalist wallpaper app.
Evaluate content against these criteria:
 
App concept:
- Themes: silence, nature, minimalism, emotional breathing room
- Target users: adults 20–40 experiencing daily fatigue
- Avoid: loud colors, commercial graphics, visually busy compositions
 
Scoring criteria (integers 0–10):
- concept_fit: alignment with the app concept
- calm_factor: how calming the content feels
- uniqueness: visual distinctiveness
 
Always return valid JSON only.
"""
 
def score_wallpaper_content(content_metadata: dict) -> dict:
    """
    Score wallpaper content for curation.
    
    Args:
        content_metadata: dict with image details
            {
                "filename": "sunrise_mist_001.jpg",
                "colors": "soft orange, light gray, white",
                "motif": "morning mist over a lake surface",
                "mood_memo": "calm, slightly melancholic",
                "season": "autumn",
                "composition": "horizon centered, generous negative space"
            }
    
    Returns:
        dict with scores and recommendation
    """
    prompt = f"""
Evaluate the following wallpaper content:
 
Filename: {content_metadata.get('filename', 'unknown')}
Colors: {content_metadata.get('colors', 'unknown')}
Motif: {content_metadata.get('motif', 'unknown')}
Mood note: {content_metadata.get('mood_memo', 'unknown')}
Season: {content_metadata.get('season', 'unknown')}
Composition: {content_metadata.get('composition', 'unknown')}
 
Return this JSON format:
{{
  "scores": {{
    "concept_fit": <0-10>,
    "calm_factor": <0-10>,
    "uniqueness": <0-10>
  }},
  "total": <sum 0-30>,
  "recommendation": "add" | "review" | "skip",
  "reason": "<brief reason in English, 1–2 sentences>"
}}
"""
    
    try:
        message = client.messages.create(
            model="claude-haiku-4-5-20251001",  # Haiku for cost efficiency
            max_tokens=300,
            system=CURATION_SYSTEM_PROMPT,
            messages=[{"role": "user", "content": prompt}]
        )
        
        response_text = message.content[0].text.strip()
        
        # Extract JSON even if there's surrounding text
        start = response_text.find('{')
        end = response_text.rfind('}') + 1
        if start >= 0 and end > start:
            result = json.loads(response_text[start:end])
            result['filename'] = content_metadata.get('filename')
            return result
        else:
            raise ValueError(f"No JSON found in: {response_text}")
            
    except json.JSONDecodeError as e:
        return {
            "filename": content_metadata.get('filename'),
            "scores": {"concept_fit": 0, "calm_factor": 0, "uniqueness": 0},
            "total": 0,
            "recommendation": "review",
            "reason": f"Evaluation error: {str(e)}"
        }
 
# Example
if __name__ == "__main__":
    sample = {
        "filename": "autumn_lake_morning.jpg",
        "colors": "terracotta, pale gray, misty white",
        "motif": "quiet autumn lake shrouded in morning fog",
        "mood_memo": "a mix of nostalgia and stillness",
        "season": "autumn",
        "composition": "lake surface fills 60% of frame, soft boundary with sky"
    }
    
    result = score_wallpaper_content(sample)
    print(json.dumps(result, indent=2))
    # Expected output:
    # {
    #   "scores": { "concept_fit": 9, "calm_factor": 8, "uniqueness": 7 },
    #   "total": 24,
    #   "recommendation": "add",
    #   "reason": "Strong concept alignment. The fog texture adds distinctive character.",
    #   "filename": "autumn_lake_morning.jpg"
    # }

Running this in batch mode, I can evaluate 100 images in 10–15 minutes. Previously I was doing this manually, one image at a time. This automation alone returned several hours to my week.

Why Haiku? For this task, Sonnet-level capability isn't needed. Curation scores are a starting point for human review anyway, and Haiku cuts the cost by roughly 10x.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Measured per-image token counts and a real monthly cost breakdown under a Haiku/Sonnet split
✦A complete, resumable exponential-backoff batch processor that survives 1,000-image runs
✦An operational checklist for absorbing malformed JSON, rate limits, and multilingual quality drift in production
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ API & SDK2026-09-17
I Send Images Twenty at a Time — The Day the 21st Image Changed the Rules for the Other 61
Sending 62 images in one request failed with invalid_request_error. The cause was the image count, not the payload size. Here is how I recounted visual tokens as 28px patches and built batches that respect count, dimensions, and payload at once.
⬡ API & SDK2026-05-14
6 Traps I Hit Building In-App AI Chat with Claude API — A Record of Getting to Production
Six real design mistakes I encountered shipping Claude API in-app chat to production — covering context management, streaming error detection, guardrails, session persistence, model versioning, and cost monitoring. Includes working TypeScript code.
⬡ API & SDK2026-10-16
Sending 40 Rows From Make to the Claude API Stops at Row 14 — Avoiding the 429 With One Subtraction
Why a no-code automation that sends spreadsheet rows to the Claude API one by one hits a 429 partway through, and how to fix it. Seven spacing strategies tested on a mock bucket, a formula for the Sleep delay, and settings that stop failed rows from vanishing.