# App Store Connect — Stuck Screenshot Remover This script helps diagnose and remove stuck App Store Connect screenshot uploads. It is useful when App Store Connect shows a red/empty screenshot placeholder and reports: > There are still screenshot uploads in progress. The script uses the official App Store Connect API. ## What it does By default, the script is **read-only**: 1. Finds the selected iOS app. 2. Finds the selected App Store version. 3. Finds the requested localization. 4. Lists screenshot sets. 5. Fetches the screenshots inside each set. 6. Shows each screenshot's `assetDeliveryState`. 7. Identifies screenshots whose state is not `COMPLETE`. It does **not** delete anything unless you explicitly add `--delete`. When `--delete` is used, it deletes only individual `appScreenshot` resources whose delivery state is not `COMPLETE`. It does **not** delete screenshot sets. ## Example problem A stuck screenshot may look like this in the API: ```text fileName: 2.jpg state: AWAITING_UPLOAD sourceFileChecksum: null width: 0 height: 0 uploadOperations: [] ``` This is the kind of screenshot that can correspond to a red/empty placeholder in App Store Connect. ## Requirements - macOS/Linux/Windows with Python 3 - An App Store Connect API Team Key - Issuer ID - Key ID - The corresponding `.p8` private key Install dependencies: ```bash python3 -m pip install pyjwt cryptography requests ``` ## Creating an App Store Connect API key In App Store Connect, open: **Users and Access → Integrations → App Store Connect API** Create or use a Team API Key and note: - Issuer ID - Key ID - downloaded `.p8` private key Keep the `.p8` file private. Do not upload it to GitHub or share it with anyone. The API key must have sufficient permissions to read and delete the app's screenshots. ## Download Download: `asc_stuck_screenshot.py` ## Basic usage First run it in read-only mode. Example: ```bash python3 asc_stuck_screenshot.py \ --issuer-id "YOUR_ISSUER_ID" \ --key-id "YOUR_KEY_ID" \ --private-key "/Users/YOUR_USERNAME/Downloads/AuthKey_XXXXXXXXXX.p8" \ --app-id "123456789" \ --version "3.2" \ --locale "de-DE" ``` You can use `--app-name` instead of `--app-id`: ```bash python3 asc_stuck_screenshot.py \ --issuer-id "YOUR_ISSUER_ID" \ --key-id "YOUR_KEY_ID" \ --private-key "/Users/YOUR_USERNAME/Downloads/AuthKey_XXXXXXXXXX.p8" \ --app-name "My App" \ --version "3.2" \ --locale "de-DE" ``` Using `--app-id` is preferable because app names can be ambiguous. ## Restricting the check to one screenshot size For example, iPhone 6.7": ```bash --display-type "APP_IPHONE_67" ``` Full example: ```bash python3 asc_stuck_screenshot.py \ --issuer-id "YOUR_ISSUER_ID" \ --key-id "YOUR_KEY_ID" \ --private-key "/Users/YOUR_USERNAME/Downloads/AuthKey_XXXXXXXXXX.p8" \ --app-id "123456789" \ --version "3.2" \ --locale "de-DE" \ --display-type "APP_IPHONE_67" ``` If `--display-type` is omitted, the script checks all screenshot sets for that localization. ## Deleting stuck screenshots **Run the read-only command first.** If the output shows a screenshot with a non-`COMPLETE` state and you have confirmed that it is the stuck screenshot, run the same command with: ```bash --delete ``` Example: ```bash python3 asc_stuck_screenshot.py \ --issuer-id "YOUR_ISSUER_ID" \ --key-id "YOUR_KEY_ID" \ --private-key "/Users/YOUR_USERNAME/Downloads/AuthKey_XXXXXXXXXX.p8" \ --app-id "123456789" \ --version "3.2" \ --locale "de-DE" \ --display-type "APP_IPHONE_67" \ --delete ``` The script will print the screenshots it is about to delete and ask you to type: ```text DELETE ``` It will not proceed otherwise. ## Important safety notes - The script does not delete screenshot sets. - It only targets screenshots whose `assetDeliveryState.state` is not `COMPLETE`. - Do not use `--delete` if you are unsure which screenshot is stuck. - Keep a local copy of any screenshots you may need to upload again. - After deletion, refresh App Store Connect and upload the screenshot again if necessary. - Apple may change App Store Connect API behavior or permissions over time. ## Troubleshooting ### HTTP 401 Check that: - Issuer ID is correct. - Key ID is correct. - The `.p8` file belongs to that Key ID. - The JWT is generated from a Team API Key. - The API key is still active. - The system clock is correct. ### No screenshot sets found Check: - app ID - version - locale - whether the version is actually the intended App Store version ### A screenshot is `COMPLETE` Do not delete it with this script. The script intentionally only considers non-`COMPLETE` screenshots stuck candidates. ## What this script was designed to solve A particularly problematic App Store Connect state is: ```text There are still screenshot uploads in progress. ``` while the UI contains a red/empty screenshot placeholder that cannot be removed. In that situation, the API may expose an `appScreenshot` resource with a state such as: ```text AWAITING_UPLOAD ``` and no active `uploadOperations`. That resource can sometimes be removed directly through the App Store Connect API, after which the screenshot can be uploaded again through App Store Connect.