Skip to main content
Apple reviews change. This page reduces the patterns reviewers cite most under Guideline 4.3; it does not guarantee approval. Treat it as a checklist, not a legal opinion.

What 4.3 actually says

Apple’s Guideline 4.3 (Spam) has two parts. 4.3(a) says don’t ship multiple Bundle IDs of the same app. 4.3(b) says don’t pile into a saturated category without a unique, high-quality experience. There’s a related rule, 4.2.6, about apps “created from a commercialized template or app generation service.” Reviewers don’t always cite the sub-letter. When they say “4.3,” they usually mean one of three things they noticed:
  1. Your binary, listing, and screenshots look too similar to another app already on the store.
  2. Your product is functionally identical to a known template (same screens, same flows, same strings).
  3. The category is saturated and your app doesn’t show a clear reason to exist.

Shared architecture is fine. Undifferentiated product is not.

Thousands of apps share SwiftUI, RevenueCat, Supabase, and OpenRouter. Apple knows this. What gets flagged is when the product, listing, and binary fingerprint all look like a copy of something else. Shared architecture alone does not guarantee approval — differentiation is product + listing + binary. Your job before submitting:
  • Keep the architecture (it’s yours now anyway).
  • Replace every user-visible string, asset, and flow that screams “boilerplate.”
  • Lead your App Store listing with your hero feature, not a generic chat screen.
  • Strip dead code that ships in the binary and exposes the boilerplate’s name.

What v2.2.0 ships to help you

v2.2.0 makes 4.3(a) hardening a first-class, automatable workflow instead of a manual grep:

scripts/appstore-43-audit.sh

Builds a Release binary, scans the main executable, every app-owned bundle file, and bundled legal/demo markdown for starter fingerprints, then exits non-zero on blocking app-owned hits (and until you replace the starter BrandConfig.appDisplayName, set production legal URLs, and rename the upstream bundle ID).

template.manifest.json

Machine-readable single source of truth at the repo root: identity surface, module graph (removable + couplings), config schema, the canonical fingerprint list, differentiation rules, recipes, and verification commands. The audit script reads its fingerprint list from here so the script, CI, and agent prompts never diverge.

docs/checklists/APP_STORE_4_3_HARDENING.md

The full playbook: binary audit, branding/identity map, metadata, App Review Notes template, and per-module removal notes (including coupling rules).

docs/prompts/AppStore4_3Hardening.prompts.md

Prompt packs for your coding agent, including the must-run starter-fingerprint cleanup (SwiftAI, Boilerplate, DesignSystem/SAI).
The App Generator (a separate, standalone macOS product, coming soon) automates this entire pass — it drives your own coding-agent CLI to generate a differentiated, 4.3-safe app from the template. It ships no LLM and is not bundled in the boilerplate. The steps below are the manual workflow you can run today on any copy of the source.

The steps to take before you hit “Submit”

1

Run the automated Release audit first

Before anything manual, run the bundled audit. It builds a Release configuration, scans the binary and app bundle, and fails on blocking app-owned fingerprints.
The upstream starter is expected to fail until you configure app-specific branding, legal URLs, backend URLs, and bundle identity. The script reports four buckets: main-executable risky strings, app-owned bundle risky strings, bundled legal/demo markdown, and configuration readiness. Third-party SDK noise is reported separately and is non-blocking. Re-run it until every app-owned hit is gone or intentionally documented.
2

Run a Release `strings` audit on the .ipa

The audit script does this for you, but if you want to inspect the binary by hand, reviewers’ automated checks compare binary fingerprints. Anything that ships in your Release .ipa can match boilerplate fingerprints.
The canonical fingerprint list lives in template.manifest.json under fingerprints.patterns. If the output contains the boilerplate’s product name, the SAI design-system prefix, dev-only client names, or stub strings, fix the source and rebuild. Don’t ship an .ipa whose strings give away its origin.
3

Remove dead Swift files from the app target

Files that aren’t referenced by your app’s UI but are still in the app target still compile into the binary. That includes example views, sample data, and demo flows you replaced.Open Xcode → Project navigator → check Target Membership for every file in Features/, Examples/, and any *Sample*.swift. Anything you don’t use, remove from the app target (you can keep the file on disk if you want it for reference).See the per-module removal notes in docs/checklists/APP_STORE_4_3_HARDENING.md in your distribution repo. Removing a module without pruning its couplings leaves orphaned code paths in the binary — see the module-coupling step below before deleting FeatureChat, AI, or Payments.
4

Rebrand every user-visible string

Search the codebase for the boilerplate’s product name and replace it everywhere a user can see it: launch screen, onboarding, settings, paywall, push copy, error toasts, support email, About screen, legal pages.
Build your branding map before you start: old name → new name, old bundle ID → new bundle ID, old support URL → new support URL. Apply it once. Don’t leave half-renamed files.The boilerplate’s design-system types use an SAI prefix (for example SAIGlass), which surfaces in the binary as DesignSystem/SAI. Rebrand the prefix with the bundled script — dry-run first, then apply after committing your work:
5

Pick a hero archetype and lead with it, not the chat tab

The boilerplate ships a chat-first home. If your app is a parking helper, a meal planner, or a study tool, chat is not your hero. Reviewers see five other AI-chat apps a day; if your first screenshot is “AI chat with bubbles,” you’re invisible.Differentiation here is enforced by mandatory archetype selection, not randomness. template.manifest.json flags differentiation.archetypeRequired, and the repo ships hero recipes in docs/recipes/hero/ to rebuild the home screen around a distinct primary experience:
  • DashboardGrid.md — metrics/cards home
  • FeedTimeline.md — scrolling feed
  • MapCanvas.md — map-centric UI
  • GuidedTaskFlow.md — step-by-step flow
  • ConversationalHome.md — chat-first (only if chat genuinely is your product)
First screenshot: the screen that shows what your app actually does (parking spot map, meal of the day, flashcard review). Second screenshot: the differentiated outcome. Chat, if it appears at all, comes after.
6

Read the module removal notes before you delete anything

Removing a module without its couplings leaves dangling symbols in the binary, which reviewers’ tooling can fingerprint. The biggest gotcha:
LLMClient and LLMMessage live in FeatureChat, and the AI package re-exports FeatureChat (@_exported import FeatureChat in Packages/AI/Sources/AI/AI.swift). You cannot delete FeatureChat alone without first moving LLMClient / LLMMessage into AI (or Core) and dropping the FeatureChat dependency from Packages/AI/Package.swift. Otherwise Packages/AI stops compiling.
If you remove Payments, you also need to remove paywall presentation hooks from FeatureSettings (which depends on Payments). The full per-module table, including which symbols to grep for and what to delete, is in docs/checklists/APP_STORE_4_3_HARDENING.md. Pair it with the buyer-facing prompts in docs/prompts/AppStore4_3Hardening.prompts.md.

Pre-submit checklist

  • bash scripts/appstore-43-audit.sh reports PASS (no blocking app-owned hits)
  • strings on the Release .ipa returns no swiftai, boilerplate, designsystem/sai, or stub matches
  • Bundle ID is yours, not the boilerplate’s com.berkin.SwiftAIBoilerplatePro
  • No demo or sample files are in the app target’s Compile Sources
  • Removed modules have their couplings pruned (see module table)
  • Branding map applied: name, support email, URLs, paywall copy
  • Onboarding pages reflect your product, not generic AI-chat copy
  • Settings → About shows your company, your URLs, your version
  • Push notifications and email templates use your wording
  • First screenshot leads with your hero, not the chat screen
  • App name and subtitle describe your product, not “AI chat”
  • Description’s first line answers “what does this app do for me”
  • Privacy policy and terms hosted at your domain (not boilerplate’s)
  • You explain in plain language what the app does and who it’s for
  • You credit the architecture honestly if asked, while making clear the product, content, and listing are yours
  • Demo account credentials work and have realistic data

Example LLM cleanup prompt

Must-run starter fingerprint prompt

If the Release audit reports SwiftAI, Boilerplate, or DesignSystem/SAI, run this first. These are starter fingerprints and should not remain in app-owned Release output.
Paste this into Claude Code, Cursor, or your editor’s AI chat after you’ve branched off main. It runs the heavy renaming pass and flags couplings before you submit.

If you already got a 4.3 rejection

Don’t panic, and don’t argue with the reviewer in the first reply.
1

Read the rejection literally

Apple’s message usually quotes the guideline number and points at one or two specific things: a screenshot, a string, a flow, or a binary similarity. Treat that as the entire problem statement, not a hint at a wider issue.
2

Run the full pre-submit workflow again

Even if the rejection mentions only one thing, re-run bash scripts/appstore-43-audit.sh and walk every pre-submit step. Reviewers compare binaries; if one fingerprint matched, others probably did too.
3

Reply in App Review with what changed

In App Store Connect → Resolution Center, write a short reply: what you changed, why your app is differentiated, and a one-paragraph plain-language description of what users do with it. Resubmit a new build with a bumped build number.
4

If you disagree, request a call

If you’ve done the work and still believe the rejection is wrong, you can request a phone call through App Review. Show up with your branding map, screenshots, and a clear answer to “who is this for and what makes it different.” Don’t argue the guideline; argue the facts.

What a boilerplate can’t guarantee

Honest version: a boilerplate can save you weeks of plumbing. It can’t tell Apple your app is differentiated, because that’s a judgment call about your product, your listing, and your category. The patterns above are the ones reviewers cite most often. They don’t cover product-market fit, content quality, or whether your category is genuinely too crowded. If your idea is “a chat app with a different color scheme,” no checklist will save you. If your idea is a real product that happens to use a chat interface, this checklist removes the noise so reviewers can see it.

Building Your App

Branding, backend, and feature customization

Deployment Guide

TestFlight and App Store submission steps

Customization Recipes

Colors, themes, onboarding, and modules

Apple Guideline 4.3

Read Apple’s wording directly