Every DIY App Store pricing script I read has the same six gaps
💡 TL;DR
DIY App Store pricing scripts work on day one. By the next paywall update or seasonal SKU, six things break: no Google Play, Apple price-point drift, PPP decay, currency mismatches, rate limits, no rollback.
I keep seeing devs script their App Store pricing. The script holds until the next paywall update, the next seasonal offer, the next SKU for an upgrade tier. Then the same six things break.
The pattern shows up every few weeks on LinkedIn, X, and Medium. An indie iOS team wires up the App Store Connect API, writes a Node.js script, defines a four-bucket PPP strategy (USA at 1.0×, Western Europe at 0.8×, mid-tier markets at 0.5×, low-PPP markets at 0.25×), and pushes thousands of price configs across 175 App Store territories in under an hour. Dry run first, then live. Conflicting future prices deleted. Logs printed. Done.
Honestly, this is a great move. I'd rather a dev ship that script than click thousands of times in App Store Connect. So this isn't a takedown. It's a map of what shows up between "script that works on the first run" and "process you can rely on through the next paywall update, the next seasonal launch, the next pricing experiment."
I'm Antonio. I built PricePush for myself first, because I had 16 app-store listings to keep priced across 175+ countries on both stores. I went down the script path before I went down the SaaS path. Most of this post is me listing the parts that bit me after the initial push worked.
By the end you'll know:
- the five things a good DIY App Store pricing script gets right
- the six gaps that show up the next time you update a paywall, add a seasonal SKU, or ship an upgrade tier (with what each one actually costs you)
- why DIY is almost never the right call 12 months in
- and the checklist for picking a pricing tool that won't get abandoned
If you're 1-2 hours away from writing this script yourself, this is the post I wish I'd read first.
What a working App Store Connect API pricing script looks like
Before the critique, the credit. The DIY scripts I keep seeing get the structure right.
Tier abstraction. They don't hardcode 175 prices. They define a small set of multipliers (1.0, 0.8, 0.5, 0.25) and a mapping from country to bucket. That's the only sane way to start. Hardcoded prices per country is a maintenance nightmare on day one.
Dry-run mode. They preview the resolved prices before sending anything to Apple. You'd be surprised how many engineering teams skip this step on internal tools and learn the hard way.
Conflicting future prices deleted. This is a real App Store Connect gotcha. If you have a scheduled future price on a SKU and you try to set a new one, Apple's API will reject the call unless you delete the conflict first. The scripts that get this right usually got it wrong once and remembered.
Direct ASC API, not browser automation. Headless Chrome scripts that drive the App Store Connect UI exist. The real problem with them isn't that they break, it's that they're painfully slow and they still need a human babysitting them. Page loads, modal waits, confirm-button clicks, re-auth flows. A run that takes seconds against the ASC API takes hours against the UI, and every Apple tweak to a button position adds another evening of manual fixes. A direct API script pushes thousands of price configs in seconds with no DOM and no human in the loop. That's the only way the speed math works at scale.
Public code. Every dev who ships one of these scripts and writes about it is doing the community a service. The next dev with the same problem gets a head start.
If you're going to script this yourself, copy that structure. The script that fails is the one that hardcodes a country list, skips the dry run, and tries to talk to App Store Connect through Puppeteer.
Six things bulk price update scripts don't handle
This is the bulk of the post. Each gap follows the same shape: what breaks, why it doesn't bite on day one, when it does bite, and what I had to build to handle it.
Gap 1: Google Play doesn't exist in this script
The majority of DIY pricing scripts I've read are iOS-only. A few cover Google Play too, but most stop at Apple.
That's fine if you're an iOS-only shop. It's a problem for everyone else. For the indie subscription apps I see in cold replies and on IndieHackers, Google Play is somewhere between 30% and 50% of revenue. The PPP impact is often larger on Google Play than on Apple, because Google supports finer-grained pricing than Apple's tier ladder.
On the first run, the iOS script handles your iOS portfolio and you're happy. The next time you ship the Android build, your CTO asks "are we pushing the same PPP strategy to Play?", and you realize the answer is "no, and the Play Console API is a different shape." Now you've got two scripts, two auth flows, two retry strategies, two ways to be wrong.
PricePush handles both stores from one push. Same UI, same preview, same approval. The internal split is two parallel modules (app/api/app-store/, app/api/google-play/), but the user surface is one button. If you want the long version of why Google Play is its own beast, I wrote about Google Play in-app purchase pricing by country separately.
Gap 2: the Apple price-point ladder is a moving target
Apple does not let you set arbitrary prices. You pick from a ladder of price points, and each price point maps to a different currency value per territory.
That ladder is not stable. Apple periodically:
- introduces new price points
- retires old ones
- adjusts territory-to-price-point mappings
- changes the "preserve base country" rules around currency rebasing
A script that imports the Apple pricing matrix CSV once and ships works the day you write it. It rots silently. The next time Apple adjusts a price point, or the next time you push a new SKU for a paywall test or a seasonal offer, your script either resolves to the wrong tier or fails the API call with a cryptic "invalid price point" error.
PricePush re-resolves the ladder on every push instead of trusting a cached CSV. Two things make this load-bearing in practice. First, the resolver hits the current ASC matrix at push time, so the price point you intended is the price point Apple sees. Second, PricePush shows you the resolved tier visually before the push goes live: a tier-snapping preview that highlights which countries snapped to a different price point than your strategy targeted. When Apple shifts a tier mapping and your $19.99 product suddenly snaps to a different price point in Argentina, you see it in the preview, not in a support ticket three weeks later.
I treat this code as a continuous work-in-progress because Apple treats their own pricing matrix as one. There's no shippable, finished version of "Apple price-point handling." There's only "kept up to date this month" or "broken since last month."
If you want the deeper view on this part, I wrote a separate piece on App Store pricing by country and how the price point ladder actually works.
Gap 3: hardcoded PPP strategies decay the moment you ship them
A four-bucket strategy looks clean in code. It's also a meaningful loss of resolution and a guaranteed source of decay.
Start with the resolution problem. A typical four-tier setup puts India, Brazil, and Nigeria in the same 0.25× bucket. Their actual PPP indices versus the US differ by roughly 20-40% from each other. For a $19.99 base price, the correct localized prices for India and Brazil end up several dollars apart in PPP-adjusted terms. The four-tier setup picks one number for all three. It's better than $19.99 flat everywhere, but it leaves money on the table in countries where PPP is more favorable than the bucket assumes, and it overprices the countries on the low end.
The deeper problem is editing the strategy later. A four-bucket mapping that lives in a Node.js constants file means changing the strategy is a code change. Moving one country between buckets, adjusting a multiplier from 0.5 to 0.55, splitting a bucket into two: each of those is a PR, a redeploy, and a re-test of the dry run. In practice, nobody does it. The strategy you shipped in month one is the strategy you'll still be shipping in month twelve, even when the underlying picture has moved.
The picture moves a lot. The World Bank revises its PPP series. CPI inflation shifts the local cost of living. FX rates move continuously against the USD base. A multiplier that fit Brazil's purchasing power in early 2024 is materially off by late 2025. The script doesn't notice. Your strategy decays in silence.
PricePush solves the editing friction with a drag-and-drop strategy editor: change a tier, drag a country between buckets, adjust a multiplier, and see the new price grid across 175+ territories before pushing. No PR, no redeploy. Changing your strategy is a 30-second operation, not an engineering ticket.
More importantly, the underlying data and the strategies aren't shipped once and frozen. I use PricePush daily on my own portfolio. Production users push prices through it daily. FX rates refresh daily against current sources. PPP indices get updated against the latest World Bank releases. When a tier produces a wrong-feeling price for a user in a specific market, I hear about it through support within hours, not in a quarterly review three months later. The built-in strategy keeps improving as more apps run through it, which is the opposite of how a static script behaves the day after you ship it.
I cover the per-country PPP math in the localized pricing complete guide if you want the longer version.
Gap 4: currency overrides aren't in any official matrix
Apple uses USD as the listing currency in many territories where Google uses local currency. The exact set of territories where this happens is not in any single official document, it's not in the ASC pricing matrix CSV, and it's not in the Play Billing docs either.
The day-one impact is invisible. You push prices on both stores, the dashboards look fine, and the storefronts render. The actual storefront price the user sees in, say, Nigeria, is what the system converts. On Apple that's USD with no rounding rule applied. On Google that's NGN with the rounding rule Google's billing config picked. Now your two storefronts are showing different prices for the same product in the same country, and you have no idea until a user emails support.
PricePush carries an explicit per-country currency override map for the known mismatches between the two stores. It's a small file, but it's the difference between coherent two-store pricing and silent storefront drift. I dug into the operational side of this in shipping prices across SKUs and stores, which is also where I'd point a dev who's about to wire up dual-store pushes.
Gap 5: flaky runs, interrupted pushes, and partial-failure recovery
At tens of SKUs and one app, the script finishes in under an hour and Apple's rate limits never trip. This is the day-one happy path.
Add a second app, a subscription product with three duration tiers (each is its own price config), or a third SKU bundle, and the call volume grows fast. Each subscription duration is a separate price config that needs its own price point per territory. A modest catalog can produce tens of thousands of API calls per push.
At that scale, three different things break, and most DIY scripts don't handle any of them.
Flaky runs. Apple's ASC API returns 5xx errors on a small percentage of calls under sustained load. A naive script logs "success" when the loop completes, but actually had a few hundred calls return non-OK that it silently swallowed. The intended state and the live state diverge. Nobody knows until a customer in Türkiye emails support about a price that doesn't match the App Store listing.
Interrupted runs. Your laptop sleeps mid-push. SSH disconnects. The runner instance gets recycled. The API key rotates. The script doesn't resume from where it stopped. You're left with a half-pushed catalog: 92 territories on the new prices, 83 on the old ones, no clear way to identify the boundary. Re-running the whole script from scratch re-pushes the 92 that already updated, which can trip Apple's "conflicting future price" errors and make the situation worse.
Rate-limit storms. Naive scripts respond to 429s by retrying immediately, getting throttled harder, and eventually wedging the whole batch. Smart scripts add exponential backoff, but they still don't know how to resume after a long pause.
PricePush handles all three with a worker queue and a per-tenant rate-limit gate. Every API call is queued, acknowledged on success, retried with backoff on transient failure, and surfaced as a permanent failure only after the retry budget is exhausted. If the worker crashes, the next worker picks up the in-flight queue and continues. If Apple throttles, the gate closes, the worker pauses, and the push resumes cleanly when the gate reopens.
The most important part: if a dozen specific (territory, SKU) combinations failed and the rest succeeded, you can hit "retry failed" and only those few re-attempt. The thousands of successful pushes don't repeat. The script doesn't know how to do that. PricePush does, because partial pushes were the second-worst pricing incident I had on my own apps and I rebuilt the worker until that class of failure was solved.
Gap 6: no history, no visualization, no rollback
The script is fire-and-forget. It pushes the prices it computes, prints success, and exits.
What happens after the push is where the gap really lives. A teammate edits the USA base price directly in App Store Connect tomorrow. Apple silently shifts a price point in March. A locale-specific override gets set in Play Console for a flash sale and never reverted. Three months later, you have no idea what your live prices are versus what the script thinks it pushed.
This is the gap that turns a one-time script into a quarterly fire drill. Every quarter, someone manually pulls live prices from both stores, diffs them against the script's intended state, and re-pushes. The script doesn't help with that. It only helps with the initial push.
PricePush solves this with three things the script doesn't have:
- Visual tier-snapping on every push preview. Before you push, you see a price grid showing the resolved price for every country, with deltas highlighted against the current live prices. When a strategy edit shifts 31 countries by a tier, you see all 31 in the preview, not in a customer email two weeks later.
- Price change history. Every push is a versioned event. Scroll the timeline to see what was pushed, when, from which strategy, with which exact numbers per country. Three months from now, when you're trying to remember what prices you set last quarter, the answer is one click away.
- One-click rollback. Pick a previous push from history and restore that state to both stores. The rollback runs through the same worker queue and rate-limit gate as a forward push, so it inherits the same partial-failure recovery and Apple-throttle handling. A bad push gets undone with one button, not a manual reconstruction of the previous state from memory.
This isn't audit-trail for compliance theater. It's operational safety. When something looks wrong in your prices, you can find when it changed, see what it was before, and revert without rebuilding the strategy from scratch. I cover the rollback model in more detail in how to update app prices safely: versioning, history, and rollback.
Why DIY scripts are almost never the right long-term call
I'll say the quiet part. Almost no DIY pricing script is the right answer 12 months in.
The reason isn't the six gaps in isolation. It's that the ground underneath the script keeps moving.
The ASC and Play APIs keep changing. Apple ships price-point matrix updates, adjusts endpoint shapes, tightens rate limits, changes error codes. Google deprecates Play Console price templates, shifts the Play Billing model, changes country-pricing semantics. Every one of those changes breaks scripts in some way. Sometimes the script silently produces wrong prices. Sometimes it errors and pages someone. Either way, someone has to fix it. Forever. API maintenance against two big stores is a continuous work-in-progress, not a one-weekend project. The right place for that work is in a tool whose maintainer treats it as their full-time job, not a script in an indie repo that gets opened once a quarter.
PPP indices and FX move continuously. The World Bank revises its PPP series. CPI inflation moves the local cost of living. FX rates move against the USD base every single day. A four-tier multiplier set that fit Brazil in early 2024 is materially off by late 2025. A hardcoded strategy decays the moment you ship it. If the script never opens the strategy file again, the strategy degrades silently. By the time you notice, you've been pricing wrong in nine countries for a year.
Open-source pricing tools get abandoned. I've watched this pattern more than once. A GitHub repo lands on Hacker News with a clean Node.js script and a thoughtful README. Indie devs star it and fork it. Six months later, the original author moves on to a new job or a new product. The strategy goes stale. The API integration breaks against the next Apple change. The forks all rot together. By month 18, the repo is a graveyard with dozens of open issues and no maintainer. Every dev who relied on the unmaintained script is now on their own, with code they didn't write, against an API they don't track, on a strategy that was untested when it shipped.
Pricing strategies without testing are guesses in code form. A multiplier that looks right on paper can move conversion 20% in either direction. The only way to know if a tier strategy works is to run it against real apps with real conversion data and watch the numbers move. A weekend-project script ships untested strategies. The dev guesses, pushes, and either gets lucky or quietly loses revenue they never measured. The most expensive part of a DIY script isn't the code, it's the un-validated strategy that runs inside it.
So the real question isn't "build or buy." It's "who is going to maintain this for the next five years, and how do you know they will?"
That's the question almost no team asking "should I just script it?" actually asks. And it's the question the answer hinges on.
How to pick a pricing tool that's still alive in two years
If the build path doesn't survive, the buy path is the real question. Here's the checklist I'd use, and the one I built PricePush to pass.
Is the founder full-time on the product? Side projects drift. The pricing tools I'd actually trust ship updates every week, respond to support in hours, and treat the integration as their primary job. If the team page says "we're a small group of indie devs working on this in our spare time," the API integration won't survive Apple's next breaking change. I'm full-time on PricePush.
Does the founder use the tool on their own apps? Skin in the game changes everything. I make my income from a portfolio of consumer apps on the App Store and Google Play, organic distribution only, no paid acquisition. The prices PricePush pushes are the prices my Argentina revenue depends on this month. If the strategy stops working, my income drops before any customer's does. That incentive doesn't exist for vendors who don't ship apps.
Is the PPP data kept current against real sources? PPP indices move. A tool that hardcodes a multiplier table once and never updates it gives you 2023 prices in 2026. PricePush ships against a curated PPP dataset I update on a regular cadence, against World Bank and FX sources. The strategy you set today reflects current purchasing power, not last year's.
Does the integration get maintained when Apple and Google ship changes? This is the most important checklist item and the hardest to verify externally. The way I'd check: look at the changelog, the release notes, the support response time. A pricing tool that hasn't shipped a change in three months either has a perfect product (extremely rare) or has stopped being maintained (much more likely). PricePush ships on a weekly cadence and the changelog is public.
Has the strategy been tested against real conversion data? PricePush's built-in PPP strategy has been validated on three layers: my own portfolio of consumer apps (where organic conversion is how I pay rent), every beta user before launch (who ran the strategy on real catalogs and reported back what moved), and every production user since (where the dataset compounds and the strategy keeps improving as more apps run it). A pricing strategy without that kind of validation is a guess in code form.
Can you test before committing? A free tier that runs real pushes against your real catalog tells you more than any sales call. The PricePush free tier connects one app and runs 10 price pushes with no credit card. That's enough to A/B PricePush's strategy against the script you would have written, before you commit to either path.
There are other vendors in this space. The checklist applies to all of them. The reason I built PricePush is that nothing in market checked all six boxes for someone running a small portfolio, and I needed it for my own apps. If you want to try it, start free here.
Frequently asked questions
Can you update App Store prices in bulk via the App Store Connect API? Yes. The ASC API supports creating and scheduling in-app purchase price configs per territory. The endpoints exist for in-app purchases and subscriptions. The hard parts are the price-point ladder mapping, the rate limits at high call volumes, and managing conflicting future prices. The endpoints don't do those for you.
Why does my App Store pricing script fail after Apple updates the price point matrix? Because most scripts cache the matrix CSV at write time and resolve future prices against the cached copy. Apple periodically introduces new price points, retires old ones, and changes territory mappings. When the cached CSV diverges from the live state, your "valid" tier resolves to an invalid one and the API rejects it. The fix is to re-resolve against the live matrix on every push instead of trusting a snapshot.
Does the App Store Connect API rate-limit price updates? Yes. Apple doesn't publish exact numbers, but in practice you'll start seeing 429s when you push tens of thousands of price configs in a short window. Subscription products amplify this because each duration is a separate config. The right pattern is exponential backoff plus a queue that can resume after throttling, not retry-in-a-tight-loop.
Can the same script update Google Play prices? No. Google Play uses a different API (Google Play Developer API), a different auth flow (service account JSON), a different pricing model (Google sets finer-grained prices than Apple's tiers), and different concepts (no equivalent to Apple's price-point ladder). You're effectively writing a second script that happens to be in the same repo.
How do I detect price drift across territories after a manual change? You diff your intended state against the live state per store, per SKU, per territory. The intended state has to live somewhere durable (a config file, a database, a versioned record of past pushes). Then you pull live prices from both stores and compare. If you don't have an intended-state record, you can't detect drift, only re-set it. This is why versioned push history and a one-click rollback matter more than they sound.
Are open-source App Store pricing tools safe to depend on? Maintained ones, yes. Most aren't. The pattern I see repeatedly: a clean Node.js repo ships, ranks on Hacker News, gets forked, then the original author moves on. Six to twelve months later, the strategy is stale, the API integration is broken against the latest Apple change, and there's no one merging PRs. Before depending on an open-source pricing tool, check the last commit date, the open-issue count, the changelog cadence, and whether the maintainer is full-time on it or treating it as a side project.
Why does a hardcoded PPP tier strategy become outdated? Because the underlying PPP picture moves. The World Bank revises its PPP series. Local CPI inflation shifts the real cost of living. FX rates move against the USD base every day. A multiplier set that fit a country's purchasing power in early 2024 is materially off by late 2025. A script that loaded the strategy from a constants file once and never re-validated it is shipping last year's purchasing power as if it were this year's.
Bottom line
The DIY scripts I see posted are useful as reference implementations. They're rarely the right long-term answer for the dev shipping them.
I built PricePush because I needed something that survived Apple's quarterly API changes, kept PPP data current without me thinking about it, recovered cleanly from partial pushes, and let me roll back a bad release without rebuilding the strategy from memory. The script I would have written wouldn't have done any of those.
If you're shipping to App Store and Google Play at any real scale, don't script this. Choose a tool maintained by someone whose income depends on the same prices yours does, and whose strategy has been tested on real apps before it ran on yours.
If you want to skip the script entirely, start free. Connect one app, run real pushes, and see how it compares to what you would have built.
Ready to automate app pricing updates?
PricePush helps you ship localized App Store and Google Play pricing in minutes.
Start Free Trial


