Business model change confusion: premium -> freemium (originalAppVersion)

Hi 👋! I want to switch the business model in my app from premium to freemium and do it gracefully for existing users. Essentially, I wish to provide newly-paywalled content for free to existing paid users (people who bought the original app).

It seems clear that I should be using appTransaction's originalAppVersion property to check against purchases made in a previous version of the app, per the documentation. However, there seems to be broad confusion over whether originalAppVersion returns the version number or the build number and how to test for it. Examples of confusion can be found here, here and here.

This lack of clarity seems especially dangerous due to the difficulty in testing these values. In the sandbox originalAppVersion returns 1.0 by default, so whether you design for version number or build number, you'll always return a positive as long as your value is more than 1. There is a real risk to unknowingly either never identify previous premium users or accidentally identify everyone as premium (essentially giving away your app for free).

For example, my app's current version number is 1.4.0 and build number is 18, so 1.4.0 (18). As this is a major change, for this new update I might as well go for version number 2.0.0, and let's say I release the app with build number 5, so 2.0.0 (5). If I expect originalAppVersion to return the version number, I would match it against 2, because anything before 2.0.0 needs to be marked as premium. However, if I expect the build number, I should check against 19 and respectively bump up my build number: 5 -> 19.

In the standard version/build "v.v.v (b)" format, does originalAppVersion return app version or app build?

If it indeed does return build, and not version, I guess I'll start all of my future build numbers from 100 just in case: 2.0.0 (100). The only way I imagine I can test this is to print the value on the visual interface in a live version of the app, and ask a random user 🤷‍♂️.

Answered by DTS Engineer in 828225022

@iniitamo

over whether originalAppVersion returns the version number or the build number and how to test for it. Examples of confusion can be found here, here and here.

The originalAppVersion property contains the original value of the CFBundleShortVersionString (the version number in the General pane of your target in Xcode) for apps running in macOS, and the original value of the CFBundleVersion (the build number in the General pane of your target in Xcode) for apps running on all other platforms.

I have an app that includes the original version number in analytics that it sends me. I'm getting this by decoding the receipt in the app, not using AppTransaction.

Examples of the version numbers that I get are 4.4.1622388619, 1.2.2 and 2.4.

This is an old app. At some point, I started using timestamps as build numbers - hence the 1622388619. At other times I had three-level version numbers, i.e. 1.2.2 is the second bug-fix update for version 1.2.

The missing part of the puzzle is what values these versions of the app had in which keys in their info.plists.

Looking at just the current version of the app, I have CFBundleShortVersionString = 4.11 and CFBundleVersion = 4.11.1718374078. I believe these are manually set in the info.plist, rather than letting xcode populate them from other fields in the build settings (it's an old app, that's how it used to work). This reports the full 4.11.1718374078 in its analytics.

So I guess that the "original version number" that you get from AppTransaction will be the same as the CFBundleVersion in your info.plist - whatever that is. You are probably letting xcode create this field, so check what is actually present in the info.plist in your final app.

If I were you, I'd parse the string from the AppTransaction. If it has one component, assume it's a build number; if 2, assume it's a short version number; if 3, assume its version number plus build. (Etc.) Then determine whether it's "new" or "old" based on whatever you have.

If you're using revision control versions or checksums, timestamps, or a global counter for your build numbers, this shouldn't be too difficult. It's more problematic if you have incrementing build numbers that you reset for each release.

Note there is also the original purchase date, which could be easier to use.

(I understand this is different on macOS.)

Accepted Answer

@iniitamo

over whether originalAppVersion returns the version number or the build number and how to test for it. Examples of confusion can be found here, here and here.

The originalAppVersion property contains the original value of the CFBundleShortVersionString (the version number in the General pane of your target in Xcode) for apps running in macOS, and the original value of the CFBundleVersion (the build number in the General pane of your target in Xcode) for apps running on all other platforms.

Great! Thanks for the swift replies 🙏.

I will clarify that the app in question is iOS/iPadOS, so it feels clear that I should be looking at the build number. Our numbering follows a v.v.v structure for version, whereas the build numbers iterate up from 1 for each version number (as listed in the General pane in Xcode). So I'll make sure the build number and subsequent value to condition against are high enough to not cause issues, e.g. 100.

For testing, will Testflight also return the default 1.0 for originalAppVersion, even with external testers?

Just curiously, has Apple ever stated why macOS gets a different treatment in this case?

Thanks for the in-depth response, @endecotp 👏. Our apps are entirely offline and we don't collect analytics (per Apple's instructions for Made for Kids apps). We could, of course, but we don't gain much insight. This particular app is already 12 years old (almost to the date), and we've only done 10 updates to it in total (only one update in the last 11 years 😀). So any fancier receipt validation is a bit beyond our scope (and unnecessary).

Since we've only done one update during this entire decade, I can be absolutely sure that all users are currently on the newest version of the app, 1.4.0 (18). So the business model change isn't that risky in this case. However, we will be converting the rest of our apps to freemium during 2025, so I need to be certain how things work and what strategy to use universally.

Just FYI, I also did research originalPurchaseDate, but I saw on some thread that it was not advised. Perhaps it's strictly only meant for subscription IAPs.

Business model change confusion: premium -> freemium (originalAppVersion)
 
 
Q