app-store-screenshots
App Store screenshot research, competitor analysis, and planning tool for iOS/macOS apps. Use this skill when working with App Store screenshots for any of these tasks: (1) Finding and analyzing competitor screenshots in your category, (2) Downloading competitor screenshots locally for reference, (3) Analyzing screenshot strategies (styles, captions, features), (4) Planning your screenshot sequence and messaging, (5) Generating a local preview website to view and compare screenshots, (6) Understanding screenshot requirements and best practices, (7) Creating exportable screenshot assets at correct dimensions.
SKILL.md
| Name | app-store-screenshots |
| Description | App Store screenshot research, competitor analysis, and planning tool for iOS/macOS apps. Use this skill when working with App Store screenshots for any of these tasks: (1) Finding and analyzing competitor screenshots in your category, (2) Downloading competitor screenshots locally for reference, (3) Analyzing screenshot strategies (styles, captions, features), (4) Planning your screenshot sequence and messaging, (5) Generating a local preview website to view and compare screenshots, (6) Understanding screenshot requirements and best practices, (7) Creating exportable screenshot assets at correct dimensions. |
name: app-store-screenshots description: > App Store screenshot research, competitor analysis, building, and upload tool for iOS/macOS apps. Use this skill when working with App Store screenshots for any of these tasks: (1) Finding and analyzing competitor screenshots in your category, (2) Downloading competitor screenshots locally for reference, (3) Analyzing screenshot strategies (styles, captions, features), (4) Researching ASO keywords for screenshot captions, (5) Planning your screenshot sequence and messaging, (6) Building screenshots using an HTML/CSS export tool, (7) Generating a local preview website to view and compare screenshots, (8) Exporting screenshots at correct dimensions via browser or Puppeteer, (9) Localizing screenshots for multiple App Store locales, (10) Uploading screenshots to App Store Connect via API.
App Store Screenshots
Research competitor screenshots, plan your strategy, build production-ready screenshots, and upload them to App Store Connect.
Overview
Screenshots are critical for App Store conversion—90% of users don't scroll past the third screenshot. This skill covers the full pipeline from competitor research through final upload.
Important: Correct Screenshot Dimensions
iPhone 6.9" (Required): 1260 x 2736 ← iPhone 16 Pro Max
iPhone 6.7": 1290 x 2796 ← iPhone 16 Plus, 15 Pro Max
iPad 13" (Required): 2064 x 2752 ← iPad Pro M4
WARNING: Many online sources (including older versions of this skill) incorrectly
list 1290x2796 or 1320x2868 as the 6.9" dimension. The correct 6.9" dimension
is 1260 x 2736. Verify at: https://developer.apple.com/help/app-store-connect/reference/screenshot-specifications/
Workflow 0 — Onboarding Interview
Before starting, gather information about the user's app and goals.
Questions to Ask
1. Is this a new app or an existing app?
□ New app (focus on competitor research)
□ Existing app (can also analyze current performance)
2. What is your app's category?
[Select from App Store categories - see category-codes in references]
3. Describe your app in one sentence:
[Used to extract keywords for competitor search]
4. What is your app name?
[Used for folder organization]
5. What are your main competitors? (optional)
[If known, provide app names or IDs]
6. Do you have Sensor Tower API access?
□ Yes (enhanced competitor finding)
□ No (use iTunes API + RSS feeds only)
7. What locales do you need screenshots for?
[e.g., en-US, tr, de-DE, ja]
Output
Create project folder structure:
{app_name}_screenshots/
├── competitors/
├── analysis/
├── your_app/
│ ├── iphone/
│ ├── ipad/
│ └── assets/
├── preview/
├── export/
│ └── locales/
│ ├── en-US/
│ └── {other locales}/
└── README.md
Workflow 1 — Find Competitors
Identify the top competitors in your category to analyze.
Step 1: Search by Keywords
Extract keywords from app description and search iTunes:
GET https://itunes.apple.com/search?term={keywords}&entity=software&country=us&limit=25
Step 2: Fetch Top Charts
Get top apps in the category via RSS feed:
GET https://rss.applemarketingtools.com/api/v2/us/apps/top-free/50/apps.json?genre={genreId}
Step 3: Filter & Rank (Optional with Sensor Tower)
If Sensor Tower API available:
GET https://app.sensortower.com/api/ios/apps?app_ids={ids}
Use download/revenue estimates to find "winning" apps.
Step 4: Select Top 3 Competitors
Present candidates to user:
## Competitor Candidates
| # | App Name | Rating | Reviews | Category Rank |
|---|----------|--------|---------|---------------|
| 1 | Calm | 4.8★ | 1.2M | #1 Health |
| 2 | Headspace | 4.9★ | 850K | #2 Health |
| 3 | Insight Timer | 4.9★ | 450K | #5 Health |
Select 3 competitors to analyze (enter numbers): [1, 2, 3]
Workflow 2 — Download & Analyze Screenshots
Download competitor screenshots and generate analysis.
Step 1: Fetch Screenshot URLs
For each competitor:
GET https://itunes.apple.com/lookup?id={appId}&country=us
Extract from response:
screenshotUrls— iPhone screenshotsipadScreenshotUrls— iPad screenshots
IMPORTANT: Fallback for Empty Screenshot Arrays
Many apps return empty screenshotUrls: [] from the iTunes API. This is common
and not a rate limit issue—the API simply doesn't include screenshots for some apps.
Fallback strategy (try in order):
-
Try different country codes:
us,gb,de,cy,tr,auGET https://itunes.apple.com/lookup?id={appId}&country=gb -
Scrape the App Store web page HTML: App Store pages render client-side via JavaScript, but the raw HTML source often contains mzstatic.com screenshot URLs embedded as data attributes.
Fetch: https://apps.apple.com/us/app/id{appId} Search HTML source for: mzstatic.com URLs containing screenshot patterns Filter for URLs with dimensions in the path (e.g., /1242x2208bb.png) -
Manual capture: As a last resort, instruct the user to screenshot the App Store listing on their device or visit the web page in a browser.
Step 2: Download Screenshots
import requests
import os
import json
import subprocess
from pathlib import Path
def download_screenshots(app_id, app_name, output_dir, country="us"):
# Fetch app data — try multiple countries if needed
countries = [country, "us", "gb", "de", "au", "cy"]
data = None
for cc in countries:
response = requests.get(f"https://itunes.apple.com/lookup?id={app_id}&country={cc}")
result = response.json()
if result["resultCount"] > 0:
app = result["results"][0]
if app.get("screenshotUrls"):
data = app
break
if not data:
print(f"WARNING: No screenshots found for {app_name} via iTunes API")
print("Try scraping the App Store web page HTML for mzstatic.com URLs")
return None
# Create directories
base_path = Path(output_dir) / "competitors" / app_name
iphone_path = base_path / "iphone"
ipad_path = base_path / "ipad"
iphone_path.mkdir(parents=True, exist_ok=True)
ipad_path.mkdir(parents=True, exist_ok=True)
# Download and verify dimensions
screenshots_meta = []
for i, url in enumerate(data.get("screenshotUrls", []), 1):
filepath = iphone_path / f"{i:02d}.png"
img = requests.get(url)
with open(filepath, "wb") as f:
f.write(img.content)
# Verify actual dimensions (CDN may return smaller than requested)
dims = get_image_dimensions(filepath)
screenshots_meta.append({
"index": i,
"url": url,
"actualWidth": dims[0],
"actualHeight": dims[1]
})
# Save enriched metadata
metadata = {
**data,
"downloadDate": str(date.today()),
"screenshotCount": len(data.get("screenshotUrls", [])),
"ipadScreenshotCount": len(data.get("ipadScreenshotUrls", [])),
"screenshotDetails": screenshots_meta
}
with open(base_path / "metadata.json", "w") as f:
json.dump(metadata, f, indent=2)
def get_image_dimensions(filepath):
"""Get actual pixel dimensions. CDN URLs don't upscale."""
# macOS: sips -g pixelWidth -g pixelHeight {file}
# Linux: identify {file} (ImageMagick) or python Pillow
from PIL import Image
img = Image.open(filepath)
return img.size
CDN Dimension Warning
The CDN does NOT upscale images. If a developer uploaded 5.5" screenshots
(1242x2208), requesting a URL ending in 1320x2868bb.png silently returns the
original 1242x2208 image. Always verify actual dimensions after downloading.
Step 3: Analyze Each Competitor
For each competitor, analyze and document:
## Screenshot Analysis: {App Name}
### Overview
- **iPhone Screenshots:** {count}
- **iPad Screenshots:** {count}
- **Actual Dimensions:** {width}x{height} (may differ from URL)
- **Visual Style:** [Device mockup / Lifestyle / UI-only / Hybrid]
- **Color Palette:** [Primary colors observed]
### Screenshot Breakdown
| # | Type | Caption/Text | Feature Shown | Notes |
|---|------|--------------|---------------|-------|
| 1 | {type} | "{caption}" | {feature} | {notes} |
| 2 | {type} | "{caption}" | {feature} | {notes} |
...
### Strategy Analysis
- **Hook (Screenshot 1):** {description}
- **Flow:** {how screenshots progress}
- **Text Style:** {short/long, benefit/feature focused}
- **Device Frames:** {yes/no, style}
- **ASO Keywords in Captions:** {observed keywords}
### Strengths
- {strength 1}
- {strength 2}
### Weaknesses
- {weakness 1}
- {weakness 2}
Save as competitors/{app_name}/README.md
Workflow 3 — Compare & Identify Patterns
Generate a cross-competitor analysis.
Comparison Table
## Competitor Comparison
### Visual Style
| Aspect | Competitor 1 | Competitor 2 | Competitor 3 |
|--------|--------------|--------------|--------------|
| Screenshot Count | 8 | 6 | 10 |
| Style | Device mockup | Lifestyle | Hybrid |
| Text Amount | Minimal | Heavy | Medium |
| Color Theme | Blue/Purple | Green/White | Orange/Black |
| Device Frames | Yes | No | Yes |
| Frame Type | Dynamic Island | N/A | Dynamic Island |
### Caption Patterns
| Screenshot | Competitor 1 | Competitor 2 | Competitor 3 |
|------------|--------------|--------------|--------------|
| 1 (Hook) | "Find Peace" | "Sleep Better" | "Meditate Daily" |
| 2 | "Sleep Stories" | "Guided Sessions" | "Track Progress" |
| 3 | "Daily Calm" | "Reduce Stress" | "Join Community" |
### ASO Keywords in Screenshots
| Keyword | Comp 1 | Comp 2 | Comp 3 | Search Volume |
|---------|--------|--------|--------|---------------|
| "calorie" | ✓ | ✓ | ✗ | High |
| "tracker" | ✓ | ✗ | ✓ | High |
| "AI" | ✗ | ✓ | ✓ | Medium |
### Common Patterns
1. {pattern 1}
2. {pattern 2}
3. {pattern 3}
### Differentiation Opportunities
1. {opportunity 1}
2. {opportunity 2}
Save as analysis/competitor_comparison.md
Workflow 4 — ASO Keyword Research for Captions
Do this BEFORE writing captions. Screenshot captions are now indexed by Apple's search algorithm (as of June 2025), making keyword placement critical.
Step 1: Research Category Keywords
GET https://itunes.apple.com/search?term={category}&entity=software&country=us&limit=25
Extract keyword patterns from competitor app names and subtitles:
"Cal AI - Calorie Tracker" → keywords: cal, ai, calorie, tracker
"Lifesum: AI Calorie Counter" → keywords: ai, calorie, counter
"YAZIO – Calorie Counter & Diet" → keywords: calorie, counter, diet
Step 2: Identify High-Value Keywords
From competitor analysis, rank keywords by:
- Frequency in competitor names (more = validated)
- Search volume (estimate from App Store suggestions)
- Relevance to your app
Step 3: Map Keywords to Screenshots
Each screenshot caption should contain at least one target keyword:
## Keyword-Optimized Screenshot Captions
Target keywords: calorie, tracker, AI, scan, food, diet
| # | Before (generic) | After (ASO-optimized) | Keywords |
|---|-------------------|-----------------------|----------|
| 1 | "Snap It. Track It." | "Scan Food, Count Calories" | scan, food, calories |
| 2 | "See Your Progress" | "AI Calorie Tracker" | AI, calorie, tracker |
| 3 | "Eat Smarter" | "Smart Diet Insights" | diet, insights |
Step 4: Localize Keywords per Market
Different markets search differently:
| Locale | Top Keywords |
|--------|--------------|
| en-US | calorie tracker, food scanner, diet app |
| tr | kalori sayacı, yemek takip, diyet uygulaması |
| de-DE | kalorienzähler, ernährung, diät tracker |
| ja | カロリー計算, 食事管理, ダイエット |
Workflow 5 — Plan Your Screenshots
Based on analysis and keyword research, create a screenshot plan.
Screenshot Strategy Framework
The "Value-Usage-Trust" Formula:
1. VALUE — What the user gets (hook) + primary keyword
2. USAGE — How it works (key features) + feature keywords
3. TRUST — Social proof (ratings, awards)
Generate Screenshot Plan
## Screenshot Plan: {Your App Name}
### Strategy
- **Style:** {chosen style based on analysis}
- **Count:** {recommended: 6-8}
- **Text Approach:** {based on competitor analysis}
- **Differentiator:** {what makes yours unique}
- **Target Keywords:** {from Workflow 4}
### Screenshot Sequence
#### Screenshot 1: Hook / Value Proposition
- **Caption:** "{ASO-optimized caption}"
- **Subtitle:** "{supporting text}"
- **Visual:** {description of what to show}
- **Keywords:** {keywords included}
- **Goal:** Grab attention, communicate core value
#### Screenshot 2: Key Feature #1
...
### Design Guidelines
- **Colors:** {recommended palette}
- **Font:** {recommendation}
- **Device Frame:** Use Dynamic Island style (not notch)
- **Safe Zones:** Keep text 120px from edges, 160px from top
- **Caption Font Size:** 140-160px title, 48-56px subtitle
- **Letter Spacing:** -4px to -5px for bold impact
### Export Dimensions
- [ ] iPhone 6.9": 1260 x 2736 (iPhone 16 Pro Max)
- [ ] iPad 13": 2064 x 2752
- [ ] PNG format, no transparency
- [ ] Under 8 MB each
Save as your_app/plan.md
Workflow 6 — Build Screenshots (HTML/CSS Export Tool)
Create production screenshots using an HTML/CSS builder.
Step 1: Generate export-tool.html
Create a self-contained HTML file that renders each screenshot at exact pixel dimensions. See templates/export-tool.html for the full template.
Key components:
- Screenshot canvas divs at exact target dimensions (1260x2736)
- CSS
transform: scale()for in-browser preview display - html2canvas.js for PNG export
- Per-screenshot customization (background, text, assets)
Step 2: Phone Frame Component
Use a modern Dynamic Island frame (not the outdated notch):
.phone-frame {
position: relative;
width: 380px;
height: 780px;
border-radius: 55px;
border: 8px solid #8a8a8f; /* Titanium color */
background: #000;
box-shadow:
inset 0 0 0 3px #1a1a1a,
6px 0 0 -2px #6b6b6f, /* Power button */
-6px 40px 0 -2px #6b6b6f, /* Volume up */
-6px 90px 0 -2px #6b6b6f; /* Volume down */
overflow: hidden;
}
.dynamic-island {
position: absolute;
top: 16px;
left: 50%;
transform: translateX(-50%);
width: 130px;
height: 40px;
background: #000;
border-radius: 22px;
z-index: 10;
}
Step 3: Typography System
Standardized caption layout for consistency:
.screenshot-title {
font-size: 140px;
font-weight: 900;
letter-spacing: -4px;
line-height: 1.05;
text-align: center;
}
.screenshot-subtitle {
font-size: 52px;
font-weight: 500;
letter-spacing: -1px;
opacity: 0.85;
text-align: center;
}
Step 4: Asset Integration
Guide for incorporating app assets:
- App icon (PNG, transparent background)
- Mascot/character images
- UI screenshots from actual device
- Position using absolute positioning with overflow for dramatic effect
CRITICAL: Serving the Export Tool
⚠️ NEVER open export-tool.html as a file:// URL.
Canvas export will fail with: "Tainted canvases may not be exported"
✅ ALWAYS serve via HTTP:
python3 -m http.server 8080
Then visit: http://localhost:8080/export-tool.html
✅ Add crossorigin="anonymous" to ALL <img> tags
✅ In html2canvas config, use: { useCORS: true }
Workflow 7 — Export Screenshots
Two methods for exporting at correct dimensions.
Method A: Browser Export (html2canvas)
Include html2canvas via CDN in your export tool:
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script>
async function exportScreenshot(elementId, filename) {
const element = document.getElementById(elementId);
const canvas = await html2canvas(element, {
width: 1260,
height: 2736,
scale: 1,
useCORS: true,
logging: false
});
const link = document.createElement('a');
link.download = filename;
link.href = canvas.toDataURL('image/png');
link.click();
}
</script>
Method B: Puppeteer Headless Capture (Recommended for Automation)
Puppeteer produces more reliable output for fonts and images.
const puppeteer = require('puppeteer');
async function captureScreenshot(url, elementId, outputPath) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Set viewport to exact screenshot dimensions
await page.setViewport({ width: 1260, height: 2736 });
await page.goto(url, { waitUntil: 'networkidle0' });
// Clone element into a fixed full-size wrapper
// (direct capture fails because of CSS transform: scale)
await page.evaluate((id) => {
// Hide all existing page content
for (const child of document.body.children) {
child.style.display = 'none';
}
// Create fixed wrapper at exact viewport size
const wrapper = document.createElement('div');
wrapper.style.cssText = `
position: fixed; top: 0; left: 0;
width: 1260px; height: 2736px;
overflow: hidden; z-index: 99999;
`;
// Clone the target element at full size (no transform)
const original = document.getElementById(id);
const clone = original.cloneNode(true);
clone.style.cssText = `
transform: none;
width: 1260px; height: 2736px;
position: absolute; top: 0; left: 0;
`;
wrapper.appendChild(clone);
document.body.prepend(wrapper);
}, elementId);
await page.screenshot({
path: outputPath,
clip: { x: 0, y: 0, width: 1260, height: 2736 }
});
await browser.close();
}
Verify Exported Dimensions
Always verify after export:
# macOS
sips -g pixelWidth -g pixelHeight screenshot.png
# Linux (ImageMagick)
identify screenshot.png
# Expected: 1260 x 2736 (iPhone 6.9")
Export Naming Convention
{nn}_{name}_{locale}.png
Examples:
01_hook_en-US.png
02_scan_food_en-US.png
03_ai_tracker_en-US.png
01_hook_tr.png
02_yemek_tara_tr.png
Workflow 8 — Localize Screenshots
Create localized versions for multiple App Store locales.
Step 1: Template System
Design screenshots with swappable text layers:
- Same visual layout across all locales
- Only text/captions change per locale
- Keep visual assets (device frames, UI, mascot) identical
Step 2: Translate Captions (Don't Just Translate—Localize)
Use ASO-optimized keywords per locale (from Workflow 4):
| Screenshot | en-US | tr | de-DE |
|------------|-------|-----|-------|
| 1 | "Scan Food, Count Calories" | "Yemeği Tara, Kalori Say" | "Essen Scannen, Kalorien Zählen" |
| 2 | "AI Calorie Tracker" | "AI Kalori Takibi" | "KI Kalorienzähler" |
| 3 | "Smart Diet Insights" | "Akıllı Diyet Analizi" | "Smarte Diät-Einblicke" |
Step 3: Export Per Locale
export/
└── locales/
├── en-US/
│ ├── 01_hook.png
│ ├── 02_feature1.png
│ └── ...
├── tr/
│ ├── 01_hook.png
│ └── ...
└── de-DE/
├── 01_hook.png
└── ...
Step 4: Side-by-Side Review
Preview all locales together before uploading to verify consistency.
Workflow 9 — Upload to App Store Connect
Upload screenshots programmatically via the App Store Connect API.
Prerequisites
- App Store Connect API key (.p8 file)
- Key ID and Issuer ID
- App already created in App Store Connect
- An editable version (PREPARE_FOR_SUBMISSION state)
JWT Authentication
const jwt = require('jsonwebtoken');
const fs = require('fs');
const privateKey = fs.readFileSync('AuthKey_{keyId}.p8');
const token = jwt.sign(
{
iss: ISSUER_ID,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 1200,
aud: 'appstoreconnect-v1'
},
privateKey,
{ algorithm: 'ES256', header: { alg: 'ES256', kid: KEY_ID, typ: 'JWT' } }
);
API Flow
-
Find app:
GET /v1/apps?filter[bundleId]={bundleId} -
Find editable version:
GET /v1/apps/{id}/appStoreVersions?filter[appStoreState]=PREPARE_FOR_SUBMISSIONValid filter states:
PREPARE_FOR_SUBMISSION,DEVELOPER_REJECTED,REJECTED,METADATA_REJECTED,WAITING_FOR_REVIEW,IN_REVIEW,PENDING_DEVELOPER_RELEASE,READY_FOR_SALEWARNING:
READY_FOR_DISTRIBUTIONis NOT a valid state value. -
Get/create localizations:
GET /v1/appStoreVersions/{id}/appStoreVersionLocalizations -
Create screenshot set:
POST /v1/appScreenshotSetsBody:
{ "data": { "type": "appScreenshotSets", "attributes": { "screenshotDisplayType": "APP_IPHONE_67" }, "relationships": { "appStoreVersionLocalization": { "data": { "type": "appStoreVersionLocalizations", "id": "{locId}" } } } } } -
Delete existing screenshots (if replacing):
DELETE /v1/appScreenshots/{screenshotId} -
For each screenshot:
a. Reserve: POST /v1/appScreenshots { fileName, fileSize, sourceFileChecksum (MD5) } b. Upload binary to the URL(s) provided in response c. Commit: PATCH /v1/appScreenshots/{id} { uploaded: true, sourceFileChecksum: MD5 }
Display Type Mapping
IMPORTANT: APP_IPHONE_69 does NOT exist in the API.
iPhone 6.9" screenshots map to the 6.7" display type.
| Device | API Display Type | Accepted Dimensions |
|-----------------|--------------------------|---------------------|
| iPhone 6.9" | APP_IPHONE_67 | 1260 x 2736 |
| iPhone 6.7" | APP_IPHONE_67 | 1290 x 2796 |
| iPhone 6.5" | APP_IPHONE_65 | 1284 x 2778 |
| iPhone 6.1" | APP_IPHONE_61 | 1179 x 2556 |
| iPad 13" | APP_IPAD_PRO_3GEN_129 | 2064 x 2752 |
| iPad 12.9" | APP_IPAD_PRO_3GEN_129 | 2048 x 2732 |
See asc-upload-api.md for full details.
Quick Reference — APIs
| Task | Endpoint |
|---|---|
| Search apps | itunes.apple.com/search?term={q}&entity=software |
| Lookup app | itunes.apple.com/lookup?id={id}&country={cc} |
| Top Free | rss.applemarketingtools.com/api/v2/{cc}/apps/top-free/{limit}/apps.json |
| Top Paid | rss.applemarketingtools.com/api/v2/{cc}/apps/top-paid/{limit}/apps.json |
| By Category | Add ?genre={genreId} to RSS feeds |
| ASC: Screenshot sets | POST /v1/appScreenshotSets |
| ASC: Upload screenshot | POST /v1/appScreenshots |
Folder Structure
{app_name}_screenshots/
├── competitors/
│ ├── {competitor_1}/
│ │ ├── iphone/
│ │ │ ├── 01.png
│ │ │ └── ...
│ │ ├── ipad/
│ │ │ └── ...
│ │ ├── metadata.json
│ │ └── README.md
│ ├── {competitor_2}/
│ └── {competitor_3}/
├── analysis/
│ ├── competitor_comparison.md
│ └── patterns.md
├── your_app/
│ ├── plan.md
│ ├── iphone/
│ │ ├── 01_hook.png
│ │ └── ...
│ ├── ipad/
│ │ └── ...
│ └── assets/
│ ├── ui_screenshots/
│ └── photos/
├── preview/
│ └── index.html
├── export/
│ ├── export-tool.html
│ ├── capture.js
│ └── locales/
│ ├── en-US/
│ └── {other locales}/
└── README.md
Reference Files
| File | Purpose |
|---|---|
| screenshot-specs.md | All device sizes and technical requirements |
| analysis-templates.md | Templates for competitor analysis |
| itunes-api.md | API endpoints + fallback strategies |
| asc-upload-api.md | App Store Connect upload API |
| export-pipeline.md | html2canvas + Puppeteer export guide |
| preview-website.html | Preview tool template |
| export-tool.html | Screenshot builder template |