This script automates the distribution of Apple App Store promo codes via Google Sheets and Apps Script.
Try it yourself: See it in action
What you'll see:
- If codes are available: QR code and App Store redemption link
- If no codes: Redirect to sample website
- Mobile-friendly interface
- Instant code delivery
Note: This is a instance using real codes for my ios app Custom Contacts for demo purposes.
- Google account
- Apple Developer account with promo codes
- Basic familiarity with Google Sheets
- Your website URL for redirects (when no codes available)
- Open the template spreadsheet
- Make a copy: File → Make a copy
- Copy and paste your apple promo codes into column 1, leave other columns blank
- Follow the Configuration and Deployment steps below
- Open the Apps Script editor (Extensions → Apps Script)
- Find the CONFIG object at the top of the script:
const CONFIG = { EXPIRATION_DAYS: 28, REDIRECT_URL: "https://yourwebsite.com" };
- Replace
yourwebsite.comwith your actual website URL - Save the script
- In the Apps Script editor:
- Run the
initialize()function - Authorize when prompted
- Run the
- Deploy as web app:
- Click Deploy → New deployment
- Choose "Web app" as type
- Set "Execute as" to "Me"
- Set "Who has access" to "Anyone"
- Important: Check "Allow access to anyone, even anonymous"
- Click Deploy and copy the URL
- Test deployment:
- Open URL in an incognito window
- If you see "unable to open file" error:
- Delete all deployments
- Create new deployment
- Ensure sheet is shared with anyone (view only)
- Try deployment again
Note: The sheet must be accessible to anyone with the link (View only) for the web app to work properly.
Make the app appear to run on your domain:
- Copy your web app URL after deployment
- In your domain provider's settings:
- Create a subdomain (e.g.,
codes.yourwebsite.com) - Set up URL forwarding to your web app URL
- Enable "Forward with masking" or "URL masking" if available
- Create a subdomain (e.g.,
- Share your custom domain URL instead of the Google Scripts URL
Note: The actual script still runs on Google's servers, but users will see your domain in their browser.
If not using the template, create a sheet with:
- Column A: Promo Code
- Column B: Status (Blank = Available, "Redeemed" = Used)
- Column C: Upload Date (Auto-filled)
- Column D: Expiration Date (Auto-set to upload date + 28 days)
- Cell E1: Reserved for notification tracking
- Script runs under developer's account permissions (intended behavior)
- End users don't need Google account access
- Only the developer needs to authorize the script
- All sheet operations are secure and authenticated
- "Execute as Me" setting ensures:
- Secure sheet access
- Protected email notifications
- Controlled code distribution
- Single point of management
- User accesses the web app URL
- System provides next available code
- User gets redirected to App Store
- Code is marked as "Redeemed"
- QR code provided for mobile users
- Developer notified when codes run out
- Automatic code distribution
- Direct App Store redemption
- QR code generation
- 28-day expiration tracking
- Email notifications
- Auto-reset for new codes
- Custom site redirect when empty
The script sends email notifications:
- When all codes are used/expired
- To the email associated with your Google account
- Subject: "All Promo Codes Redeemed or Expired"
- One-time notification (resets when new codes added)
Common issues and solutions:
- Authorization errors:
- Ensure you're logged into correct Google account
- Re-run setup functions
- Check deployment settings
- Codes not distributing:
- Verify sheet structure
- Check date formats
- Ensure codes aren't marked as used
- Script errors:
- Check Apps Script logs for error details
- Verify CONFIG.REDIRECT_URL is properly formatted
- Ensure all setup steps were completed
- "Unable to open file" error:
- Ensure sheet is shared (Anyone with link - Viewer)
- Create new deployment from scratch
- Check "Allow access to anyone, even anonymous"
- Test in incognito window
- Clear browser cache and try again
- Add new codes directly to sheet
- System auto-updates dates
- No regular maintenance needed
- Script updates preserve settings
- Zero-touch operation
- Automatic tracking
- User-friendly interface
- Secure distribution
Important: Each developer who deploys this script needs their own verification if they plan to distribute their deployment widely (>100 users).
When you deploy this script from GitHub:
- You create your own instance of the app
- You'll need your own verification if serving >100 users
- The verification process applies to your deployment
- You'll need your own privacy policy and terms
Steps for Your Verification:
-
Prepare Required Documents:
- Your own Privacy Policy
- Your own Terms of Service
- Your application homepage
- Demo video of your deployment
-
Update Script Properties:
- Add app name in script properties
- Add support email
- Add links to policy documents
-
Submit for Verification:
- In Apps Script editor: Deploy → New deployment
- Click "Configure OAuth" (under "Web app")
- Fill in Application Details:
- Application name
- Support email
- Developer email
- Links to privacy policy & terms
- Click "Configure Consent Screen"
- Complete OAuth Consent Screen in Google Cloud Console
- Submit for verification
Required OAuth Scopes Explanation:
https://www.googleapis.com/auth/spreadsheets: Manage promo codeshttps://www.googleapis.com/auth/script.scriptapp: Create triggershttps://www.googleapis.com/auth/script.send_mail: Send notifications
Note: For internal use or <100 users, verification is not required for your deployment, but users will see an "unverified app" warning.
Keep the template and GitHub version in sync using clasp:
-
Install clasp:
npm install -g @google/clasp
-
Login to Google:
clasp login
-
Clone the template script:
clasp clone "1tkYNCup-ZtKozkpF6s96E__1DcsUUtso0afIQbF-poE" --rootDir ./src -
Push updates:
clasp push
-
Pull changes:
clasp pull
Note: You'll need to enable the Google Apps Script API in your Google Cloud Console.
For template maintainers:
- Make changes locally
- Test changes
- Push to both GitHub and template:
git push origin main clasp push
This ensures both versions stay synchronized.