mergeconflict292 === [00:00:00] James: Frank. I am literally ridiculously excited for this week's podcast because I've been talking about this topic for weeks. I've been trying to implement it for weeks. I've been testing. All weekend long. And I think I have it in like the perfect spot. And at the same time, I'm pretty excited because there's this new drink that I've been trying. That happens to be our sponsor this week that I'm going to tell us about later in the show called magic mind. It's absolutely delicious. You've been trying it. I've been trying it and it's really been helping me get through. Implementing in-app subscriptions into my applications. Look at a buttery smooth. That was Frank. [00:00:44] Frank: You need all the help you can get. Don't, you know, I'm actually quite afraid of this episode. So I'm glad that you're all jazzed up because I've been fearing this for awhile. It's fun to talk about subscriptions and payment systems and all that at a high level, especially when you're egging me on ridiculous pricing models for my apps. But then the rubber must meet the road and you must actually implement the stuff. And so I am both looking forward to, and painfully want to avoid all the scary, hairy details here about. [00:01:19] James: So let's go through this one more time with the, how do you monetize your app? Well, you can have free apps that don't take any money and guess what? You don't have to implement. You don't have to implement anything. That's good. There's another monetization where you do make money and you charge people for the app. That's the thing that Frank, [00:01:38] Frank: you put a price on it and people pay it and then you just you're. You're happy. And life is simple. It's the good [00:01:44] James: life. There's a hybrid between the two of those where you have to do a little work, but not too much, which is, this is a free app. And let me have you unlock some features with a promo code and, you know, I'm a big fan of that, Frank? [00:01:58] Frank: Yes. Uh, varying degrees. We, we we've pushed you along in different directions throughout the many years. Um, because yeah, you have put, you put in a pro mode when you added the graphing capabilities to your app. Uh, and I always thought that was a good idea. But that was a one time purchase if memory serves, because we were talking about subscriptions back then, but we weren't quite sure what to do, but at some point between then and now you got the subscription religion or [00:02:29] James: something. Yes. I would say I got the itch to start making more regular money on occasion. So, uh, for financial, try it out too, because I've had the inept billing plugin for years and I've used. For the scenario of a one-time consumable non-consumable purchase. There are consumables too. Like you're making a game, you're gonna have a consumable where you can buy things over and over again. But a non-consumable is that you bought it and you own that thing for the lifetime. So like the promo, now the issue with those two things that we outlined the Frank tried and true mechanism, and the James' tried and true mechanism is that you don't make recurring revenue, which is what you just pointed out. Uh, for greater or worse, right. I think that ideally it would make a great product and you're increasing the amount of users that you have then you continuously, you know, um, will generate more revenue. But what if you get less downloads? You know what I mean? And people still want to use your app. [00:03:31] Frank: Yeah. I mean, ever since the beginning we've wanted subscriptions because yeah. Um, so. Paying $10 for your app and you maintaining it, you know, a couple of releases every year, you know, something like that. It's quite a bit of work to do that, and you're not getting any recurring revenue. So it's not a great situation. The old one, honestly, I have, I keep falling back. I blame simplicity, you know, that's my great. Tragic story there, but at the same time, obviously subscriptions will make you more money in the long run. As long as you don't mess up the model too much, or, you know, the world changes and people just hate subscriptions. But right now in this economy, subscriptions are doable. [00:04:20] James: So descriptions are doable. I think people are a little subscription fatigued, but if you. A really engaging application and you have features that people want. I do believe they're willing to pay for it. And my, my thought process right now is to have a very low entry fee for people to get more people, just to try it out over the long time subscribers. Now, the reason I never went down the subscription route and I'm interested why you didn't, but my reason is not that I didn't, that is not that I didn't want to. It's just that. I knew that they were going to be extremely complicated to implement because, um, non-consumable, in-app purchases are so easy to implement. Uh, and I looked at the documentation for subscriptions. I was like, there's no way I can possibly do this. Like when you do a non-consumable purchase, the person buys it and it's in their purchase history. And if the. They bought it. Like it doesn't expire ever. Like they either bought it or they didn't buy it. And you have a restart button and a buy button. And like, you don't have to calculate anything. You don't have to keep track of stuff. You don't have to be like, oh, it's the end of the month. Like, what do I do now? Like, do it take away the function, not know they just get to keep the functionality. So for me it was I'm don't want to say lazy, Frank. I want to say there was a very large time committed. Um, for implementing and trying out subscriptions in my applications. And now that I have, I'm still not even at the 100% I've done it, correct mechanism because subscriptions are very complicated, which we're going to get into today. But what is your reason, Frank? Is it because you don't think it's a good model for your app, the complications or don't break it? If it is. [00:06:12] Frank: Um, yeah, well, honestly the biggest thing in my way right now is I don't know what the upgrade path is for people, because I don't want to have someone to buy the app for. You know, $10 today or whatever I'm selling it for. Um, and tomorrow say, hi, all the features are gone. Now you got to pay for the subscription to get all those features back. So that would be, I don't know how to handle that transition. I am also a little worried about, as you said, tried and true. Um, I make a living off of these apps. That's my income. That's my salary. And. I know what I'm making right now. Anytime you introduce change, even though the probability that the change will be positive and good is pretty high, there's still a chance. It could be lower. Maybe a everyone gets the free version and, uh, I put the scale wrong and the free version is. And no one ever needs to buy the pro version. So I screw up in that way. Um, so many different ways to screw up. It's almost easier with a new app, I guess is all I'm saying here with the existing apps, it's much harder. So that's why I'm definitely looking to do this with. [00:07:26] James: That totally makes logical sense. You know, I did that with, um, with island tracker. It was paid if you remember, and then I made it free and did an in-app purchase to see if it would stimulate download growth. Cause I wasn't getting a lot of downloads. Uh, I definitely did get more downloads. I don't think I got more people paying necessarily, but at the same time it was never generating a lot of income. Right. So it wasn't something where I was like, oh, let's see if this work like nothing was going to work. I think it was a great. In a very extremely crowded market and maybe I just didn't market it well, bad name, whatever. But in that situation, the nice part is that I had a backend for the application. There were, there were in quotes, user accounts, which we've talked about in the podcast before. And I created a little structure that I backdated everyone that bought the pro the full version, and they could restore that from the server, uh, which was nice. So that. If you were new and installing it and you tried to restore it, well, you didn't already buy for the full price. You got to buy the in-app purchase for, you know, dollar 99 or whatever one time fee, you know? And I was just like, here's this here's that? And you can just try to get more users. Um, so that was the only way of doing it. But I think for Europe's they don't have servers and log-ins and things like that. No. [00:08:43] Frank: Uh, but I think we both agree that that's the right way to move forward. If, if I want to do this, um, basically give people six months to create an account and be like, look, uh, you have the full version right now. If you want to keep using the full version, I'm really sorry about all this. I'm really sorry that you have to create yet another account, but, uh, if you want the features, you got to go do this. Uh, I think that's, it's not great, obviously, but it's reasonable. I think people could tolerate it. Uh, it's. I did it for Calca well, let me rewind, um, something I'd like to ask you too, is whether you can just do receipt validation to also help with that upgrade process. Could I just, not even like the full server receipt validation, I think you can just talk to the store and just ask for the app's receipt itself. And even you don't even have to ping it off your own server, right? That could be a way to, you could just mark a date and say, I know for a fact, uh, prior to the state, uh, it was the full price version posts that day. That's the free. [00:09:47] James: No, I think that's totally true. I believe that you can do receipt validation now. I don't know if receipt validation is if you buy the app or if it's only for an app purchases, [00:09:57] Frank: the one I want to know. Yeah. Yeah. I believe back in the day you could only, because piracy was a big deal back in the day. I remember people used to always send me screenshots on my app on all the pirated sites and for a little while there I cared. And so I wrote that kind of code. I just don't know what the current state-of-the-art is and that kind of stuff, but definitely something I'm reminding myself now that I should [00:10:19] James: go look at. Yeah. The other thing you could do is what I did in the application at the same time, as I did an update to the app when it was paid and when they open the app, it stored basically a cookie in the, uh, in the, I don't think I put it in the key chain, but I just put it in the shared preferences. Key chain would have been better cause it's backed up, but it was a token. I've I have that version and then I try to restore that and then I just, oh, it all automatically know. And if you're in the key chain that would carry around from device to device, but that wasn't. One thing that I was like, okay, this would probably work most of the time. Um, and maybe only 10% of my people are when they get a new device would need to do that. Yeah. The [00:11:02] Frank: iCloud, it always just comes down to iCloud and you don't even have to use key chain for that. Cause you know, you're not trying to prevent hackers or anything. You can just use the ubiquitous, uh, key value store that's available. And most apps use either one, but it had all the same problem. Always comes down to, you got to make sure you have an iPad. Uh, the person's logged into iCloud at least once while using the app. Yep. Okay, good. I didn't mean to side sidetrack us. Uh, so going back, I, I haven't done, um, subscriptions before, but what I did was consumable in-app purchases that still had a time associated with them. So you could buy. Three months of using the app six months of using the app. And this was before they allowed subscription. So ubiquitous way, that's perhaps another reason why I don't have subscriptions. Hey, everyone, I'm old. I've been selling apps forever and they didn't allow this. I mean, at first it was only news apps. And then you had to show that like, it was a significant strain on you in order to do subscriptions. Now they don't really care. You just do subscriptions. Um, So, what I did was consumables with time limits, but I almost felt like I had to go through all the same logic. You know, I had to check the day, double check the day, blah, blah, blah, accumulate a bunch of them resolve all the differences and all that. So I feel like I got a little bit of training for this, but anyway, please continue with your story and tell me all the terrible parts [00:12:31] James: I am. I'm thinking that you Frank. In-app subscriptions without actually doing enough subscriptions because that process that you outlined is exactly what I had to do. So let's talk about just in-app subscriptions without having to think about the intricacy of the pricing model. If you already had a paid version or you already like me have a pro mode in your application, let's just. In-app subscriptions and we feel need to do Greenfield. It's a new ad. So it's a, it's a wonderful brand new world five years. And it's like the first thing that you CA you haven't written any code of your app yet, but you know, you want to do an app subscription. So that's where you [00:13:13] Frank: write the accounts with them first. I love it. I love where your mind is. [00:13:17] James: Okay. So, and as subscriptions, we've all done an in-depth subscription, but when you're in. Google play or your in app center connect. You get to pick a few things. You get to pick an identifier, a visible name, a description. These are the same for all in-app purchases, but then there's the kicker, which is you get to set a price and a timeline, and a few other properties such as is there a free trial? That's a new thing now. And also how many days are you going to enable? Them to, um, have a subscription while the payment is pending. Yeah. Oh [00:14:00] Frank: yeah. Yeah. Uh, what's the default there seven [00:14:03] James: days. [00:14:04] Frank: Okay. Sounds reasonable. [00:14:06] James: So [00:14:07] Frank: lesbian. I don't, I don't, I don't try to fight the scammers. You know, if you can hack Apple's payment system. Good on you, you know, you can use the circuit app. Yes, [00:14:17] James: I, that is the, you know, and that's how I did all my inept purchases. I never did receive validation. I was like, no, who's gonna is fine. Like if T five people want to get around it, that's fine. Um, now that being said, uh, to keep it simple, I was like, no free trial. No, just you, you haven't got the thing or you didn't get the thing. It's fine. You know, I think I would do free trial if this was a very expensive in a purchase because you get to choose how long you can do. I think it's like one week, one month, and then like six and three months, six months, one year, whatever you can do, like a lots of different places. [00:14:53] Frank: I'm assuming from the apples management side, they can only buy that one once. Is that how it works? Is it up to you to [00:15:01] James: hide it? No. So if you, as I've tested this, I'm wondering for both non-consumables and subscriptions, um, once they buy it, if they try to buy it again, um, it will return this purchase to you automatically and say, Hey, they, they already own this. Yeah, and they won't let them buy it again at all, which is super duper nice. It's absolutely [00:15:26] Frank: delightful. Okay. So let's, let's, uh, start at the beginning here. Let's say you want to offer, um, what, $2 a month and $10 a month. And then. Are you, are we going to talk about buyout prices or not different episodes? Just subscriptions. [00:15:43] James: That's next? Let's. Let's talk about my final implementation at the end of the day. So we have, [00:15:47] Frank: you have two price points, then $2 and $10. You probably only have one price point. Is that [00:15:51] James: right? One price 0.1 month. $1, maybe 49 cents. I'm not sure. Um, 49 cents is an option inside of apple. Google. You can set whatever you want. You want it to be 10 cents. It could be 10 cents. You want to be one penny a month. It could be one penny a month for all daycare. I love that. [00:16:09] Frank: I love that. I hope someone releases the one penny a month up. [00:16:12] James: Yeah. Um, and so you can send me, [00:16:17] Frank: right. So in app store connect, let's say, sorry, iOS person. Um, I would go in there. I'm not setting. An expiration date, a time limit or anything because it's a subscription, right. I'm just saying monthly. So I choose monthly versus weekly versus yearly. Do I choose that? [00:16:33] James: That is correct. Yeah. You get to choose any beautiful dropdown, how much you want and for how long this subscription. [00:16:42] Frank: The payment interval is really what that is. [00:16:45] James: That is correct. And you can have auto renewing and also non not renewing, not auto renewing, which I don't know how you'd ever do that. It's not over doing hello. You know, just saying, [00:16:56] Frank: just trying to sell some apps over here, people [00:17:00] James: and they call these things subscription groups. Multiple subscriptions into a group. So you can have a pro subscription group. You could have a elite subscription group, and those could have the different month intervals in there basically. [00:17:14] Frank: Right. So you're not getting fancy though. Again, 1, 1, 1, 1, 1, 1, 1, 1 [00:17:20] James: rice, but, okay. Yeah. Yeah, you can do one week, one month, two months, three months, six months, one year. That's all your options. That's it. So you're not going to give [00:17:28] Frank: them a yearly break. You didn't decide to do that. [00:17:31] James: Um, no, I just, you know, I have the logic that you have to implement it. The application gets quite complicated. So is [00:17:41] Frank: it both, or I guess you put them in a group. If they're in a group, can they buy only one out of the group? That'd be nice. [00:17:48] James: That would be nice. Oh, then there's also the, so there's also the thing that I didn't talk about. Upgrading subscription. So for example, maybe I want to move from one month to six month and I can upgrade from or downgrade. So maybe you have a bronze, silver, gold, and they can upgrade and downgrade in your application. That's again, way too much. It's too, too complicated. See how complicated it gets really quick. [00:18:13] Frank: Sorry, but just, I have to know you brought it up, it's your fault. Um, and so that would be in a group, for example, you could upgrade within a group or can you upgrade even out of group? [00:18:22] James: I'm not positive. I think it's inside of a group, but I've never done it. So I don't actually [00:18:28] Frank: fantastic. Okay. Keep it simple as what James is saying right now, but I can see definitely the benefit of giving a yearly discount over the monthly price. That's the only reason. Yeah. So little details to look. Yeah. [00:18:42] James: It could be two. And then, you know, I think that's going to be like, based on feedback, I could say, okay, like, Hey, you know, is it a one month, six month, one year? Like, what does that look like? Because many SAS services, software as a service, they do that, right? They say, here's your monthly, but here's your yearly. And, uh, the yearly makes it really easy because you don't need to check the server for a whole year because they upgraded to pro for a whole year. [00:19:06] Frank: Well, nice segue. Um, just to state the obvious here, I assume when you're at boots up, it checks all this stuff. I assume whenever it comes back into the foreground, after being in the background, it checks all this stuff any other times. [00:19:21] James: So let's talk about that. So implementing a purchase of an in-app subscription is the same process. So the code is literally the same, except for you say. This identifier, which is a subscription, and then they buy it and, and you, you get that, that, um, transaction information back that they've purchased it and they're good to go. So in that instance, the, the process of if you're doing a consumable non-consumable, those are identical between the platforms it's really up to you. And this is where it gets complicated. You have to decide. When do you check, how are you storing when they purchased it? When it expires, are you going to give them a little leeway? Um, um, what happens when they re uninstalled your application? Re-install your application? What happens when they cancel a subscription? What happens if. Refund your subscription, which is different than canceling by the way, because when you cancel the subscription, still goes to the end of the month. You don't get a refund. It just doesn't renew. You're locked in, but they can request apple to refund, which they can also do with a non-consumable, which by the way, I don't do anything for. Two people ever in three years have ever asked for a refund. And it was only because one of them, I couldn't solve their Bluetooth issue. And I said, ask for a refund. That's totally cool. And in fact, you'll keep the promo because I don't check if you do the refund. Um, but we'll, [00:20:51] Frank: we'll talk about that. Okay. Let me pause you then. Um, Rewind. I know from the past that I like to query apple servers to get all the prices of things. So the purchasing side you're saying is pretty simple. You just query all your subscription IDs, get your up-to-date prices, display those handle the UI. That should be easy. But in the checking part, this is fascinating now. So I assume that there's a status code, cause there's always a status code. There's canceled. Made sense to me, the refund isn't just yet another status code. So are you being lazy in that you're just not handling that status code or is it just more complicated? [00:21:29] James: Ah, Frank, you would think there's a canceled and a refunded token and information and the purchase information, but there is no, [00:21:37] Frank: ah, it's purchase information only not canceled or refunded information. Is that what I mean? Jackpot. Fantastic. So how do you, how does one detect a cancellation James? [00:21:50] James: Well, let's talk about that, but before we do, let me actually tell you a little bit about how I've been mixing up my mornings with a brand new, awesome productivity drink alongside my coffee. Cause you know, Frank, I love coffee, Frank. You know, I love it. [00:22:03] Frank: Oh, it's true. It's true. You can't get this guy to stop talking about. [00:22:07] James: Every morning now I'm not only having my amazing delicious coffee, but I'm also mixing in this magical elixir called magic mind. Now, magic mind is really, really cool because I have a ritual in the morning, but they reached out. I've been trying this out almost every single morning and it's helping me boost my productivity. And I'm not a person that's like one a mess with my coffee. Right. But this thing is really cool. It's kind of like a little shot of green. Good tasting stuff basically is what I consider it, but that good stuff are just 12 natural ingredients like Masha, which I love all the time. I love matcha whenever I can drink it. And other adaptogens and nootropics that help you focused and fight stress. I've been trying out magic mind with my morning coffee. And so as either, so have you, and I've been taking it before work with. It's made my mornings and afternoons an absolute delight now is really cool because it's not only delicious to taste. It's all natural. Okay. A hundred percent in it. And if you're looking to maybe reduce your coffee consumption, I'm not, it can help you do that. Um, but one thing that I think is really cool about it is. The company is 100% carbon neutral. And for every bottle they sell, they get 5 cents back to mental health charities and services at the same time. So it was a really cool company, really good people behind it. And I've really enjoyed it. Now, if you want to give it a try, magic mind has an exclusive special offer for all of our listeners of merge conflict. Okay. If you want to give it a try, just like I have been doing and now drinking it almost every single morning, you can go to magic mind dot. Slash merge magic mind.com/merge, M E R G E. And you can use exclusive discount code at checkout to get 20% off your first order merge. Merge 20 is the coupon code. Get it 20% off twenties in the name you can give it a go. So go to magic mind.co/merge coupon code merged 20 to get 20% off your first order and give it a try. I really enjoyed it. Heather's been loving it. And even you Frank, who doesn't like to add in anything else into Jay's coffee ritual gave it a. Oh, [00:24:22] Frank: yes, it is a sparkly little joy. Uh, I, I used to try those like crazy energy drinks back in the day. And I had gotten off of those, but this one is a nice, like you said, nice few natural ingredients and nice and yummy. [00:24:36] James: That's a great point too. I hate energy drinks and I like this stuff, cause it's not an energy drink. It's like one of those nice little shots of goodness that you want. And I forgot to mention they also have a money back guarantee. So if you don't like it, they'll give you your money back. No questions asked. So who doesn't love that? Um, thanks. Magic mine. Um, for delicious goodies. Thank [00:24:56] Frank: you magic mind. Yeah, I did get a free sample and I totally did like it. It's just, it's just cheating to get free samples, but I followed the structure. I [00:25:06] James: didn't have to pay, although I am not got a subscription gun. So now here's the other thing about subscriptions, right? When you get that information back, you just get, if it's like a pending payment or it's purchased. And pretty much if it's purchase, it's good to go. So you get error codes and you handle those gracefully, but again, you don't get a status of canceled to refund it, which is. Now the only way to do these on both apple and Google is to actually do receipt validation. No. Yeah, no. In fact, in fact, they recommend that you set up a server that listens for web hooks. So you get notified when people can. [00:25:47] Frank: Yeah. Yeah. Boy, what would it be nice to live in a world where I just had a web server for every single one of my apps, listening to apples, every little whim instead of them just putting in the API, whether it's canceled or refunded. Oh, okay. So that's the true answer is, um, to do receipt validation, which does this version does require a server is. [00:26:13] James: Yeah, I believe so. I mean, I guess you could do tons of receipt validation in your app on start-up and a bunch of other things that seems really complicated. I feel as though the reason subscriptions are complicated and continue to get complicated in this scenario is if you want to do them 100% proper from end to end, and it would make sense if you were a company. That had a website and a mobile app. And you had your own auth store backing database, like you're saying, and can handle it end to end, but that's not me, Frank. So that's not what I. Okay. [00:26:49] Frank: But at the same time, you still want to expire these things somehow. Right? So if they paid for a month, I'm assuming if they canceled, you're still going to handle that somehow. Right? James, are you just going to give them the features forever? [00:27:02] James: That's a great, that's a great point. So that is one nice thing about being like, Hey, this is only every month compared to a year. Is that at the end of the month? They don't get it again if they cancel it so they won't have any more. Receipts. Sorry. [00:27:16] Frank: Right. So there is a new purchase, a receipt for every single month. Is that what you're saying? [00:27:23] James: That is correct. That is [00:27:25] Frank: that's going to accumulate after 10 years. That's funny. [00:27:28] James: So I'll tell you about this in the testing, because don't worry. I have about 58, um, test flight notifications because purchasing subscriptions are funky in test flight. So yeah. So apple will give you a brand new. For every single, um, renewal in the system. So the original purchase and every renewal from my understanding, Google only gives you the most recent. So regardless in your code, the only thing you need to do is get all of your receipts. And order descending only by the transaction date. [00:28:07] Frank: Uh, technically the end date you should add on, but length of it and then descend after that. But yes. Got it. Yeah. That sounds, that actually sounds doable. I'm in, I'm in. Yeah. [00:28:18] James: Yeah. So, so what I do in my code is I store a few values. [00:28:25] Frank: I'm sorry, I I'm just thinking out loud here. I'm just interrupting. Um, it just occurred to me though, the real downside of the not handling the cancellation, like you said, worst case someone gets a free month out of you, but if you're doing yearly, it would be a little. Worse a lot, bit worse, quite a bit. Correct. At worse. So if you are going to offer you early, maybe you do want to put the effort into putting that server up. [00:28:50] James: And I would say absolutely. I would say absolutely. Or figuring out how to validate things in, even if it's in the app or do you receive validation or something else? I would say. Do that. And in my, in that billing, I have how to do with Azure functions and stuff like that. John Donne, the peppers wrote a great article on how to do it on his blog too. So I'll definitely link to my up billing where you can see the documentation on how to do that. But yeah, I agree. So in this scenario I'm like, that's fine, right? Not a big deal. So what I do in my app, Frank, is I have three NS user defaults preferences that I store. Hmm. Okay. One is, have they ever bought a subscription? Ever. Okay. Love it. [00:29:34] Frank: Okay. But these are to be clear, these are things you're backing up to iCloud or something you want this cross device, or you want this on [00:29:41] James: device just on devices. Fine. Because when they restore their purchases, you want. Yeah, they update. So if you uninstalled and reinstalled, you're going to have to go into settings, restore your purchases. I'll figure it all out. Right. Um, okay. So have you ever bought a subscription ever in your entire life? That's one, two. When does that subscription expire? Yeah. Okay. Important. Which is very important, which would normally be one month from the transaction date. However, James over here gives you an extra five days. So, [00:30:19] Frank: so w we'll get into UI stuff. But, um, I'm curious if you pop up like an alert, like five days left, four days left three days. [00:30:26] James: Now, well, I would, if it wasn't auto renewing, but it is auto renewing. So [00:30:32] Frank: you can't really offer it because when do you actually get the payment receipt? Are we talking like, is that accurate to the minute? Should I pad things by hours, days, months, not [00:30:44] James: months. So, so that's a great point. So. The reason I decided to pat it by five days was I wanted to basically give my users enough time where if their credit card had expired, they're going to get an email. They're going to go and update it. It's going to go process. I'm thinking five days is good. Um, what NLS also, you're giving them an extra five days who cares at the end of that. You know what I mean? Um, [00:31:10] Frank: But I, I'm sorry. I thought that you said earlier that apple helped out with some of us where you could say there was a grace period of seven days, but maybe that's not related. [00:31:21] James: Yes. But I don't know how that works. And so now the other thing that I, um, another bullying that I, I, I use another value is should I show a, pop-up telling you to refresh the status of your. Hm. Okay. Hm. Yeah, it's a lot shorter, but so here's, here's what happens. So when you buy a subscription from me, I have the, for the very first time I say, Hey, you totally bought a subscription. Thanks for being awesome. And let me set the expiration date. Um, two, one. So daytime on that UTC that comes back from the transaction. Plus one month plus five days, I store that in my little C secure storage. And I say also, I definitely want to do that. Pop-up at some point in the future. So store that because they have a valid subscription. [00:32:16] Frank: Okay. Wait, sorry. So why do you want to pop up if they have a valid. [00:32:21] James: We'll get to that. Thanks for right. Got it. Now I do the same exact thing. If you also restore your subscriptions. Okay. Because let's imagine you install that on another device. You go to buy it again. Well, you just go in and you say, Hey, restore my purchase. I do the same thing. I say, Hey, I look at all of the receipts. I order descending lead by date. And I say, okay, Frank bought a subscription one week ago. Let's add one month, five days to seven days ago from the transaction UTC. Super simple. And you got you're good to go. You've got probaby. You are good to go. You got everything now, Frank, one month, five days has passed. What do I do? Because now you open the app up and you don't have pro because that Boolean, that I'm checking and that date time have now expired because the daytime is past the one month, five days. What do I do, Frank? What would you [00:33:19] Frank: do? I assume your app just crashes. If that is the tricky scenario to handle, [00:33:25] James: that is what I thought of doing. And then I said, no, I'll be a little classier. So the first thing that I do is I use that second bullion to say, should I show a pop-up? And I'm not really sure. I don't have like a best, I, I, this is what I did because I didn't know any better. And there's really no guidance. So what I did is I said, Hey, it looks like your one month subscription. Um, status needs to be refreshed. Do you want to refresh it now or later? Because maybe you don't have internet. Maybe you're just like, I'll do it later or whatever. Not a big deal there. Yeah. And if they say refresh on that page, they don't have to navigate anywhere. I go grab all the receipts, pull them all down, try to see if they bought a new one and if they did, and if it auto renew and I say, thanks for being awesome. You're the best person in the world. Rad. You know what I mean? If they say maybe later or no matter what they press, I basically now say don't show this pop-up again. Right? Because they may have canceled it. I don't know that. So they might say maybe later, and then I'll just never pop that up again. So I don't keep bugging them. I don't want to bug them ever, but I'm going to be bugging them every one month and five days, one time. And it takes five seconds to refresh the thing. But I, I that's what I did. I guess I could have done it silently. But then I was like, what if something goes wrong and they started a ride really quick and I'm doing something? No, no, [00:34:49] Frank: I think it's fine. I think everything honestly, a little bit overly subtle. Um, I'm imagining, sorry that this is how I'm going to implement it. Like a terrible person. Um, I'm going to have a lot of the pro features exposed in the UI. And when you tap on them, it's going to bring up like this how to buy screen and refresh your numbers screen. I'm basically going to have just one screen that does everything. And so it makes sense whether you want to, you, you want to very manually control, uh, whether that gets presented or not. But at the same time, I think every time they click on a feature, that's a pro feature. I'm going to pop it up anyway. So I think you're being very subtle and that's very generous of you. Um, it's a free app. You're allowed to be a little obnoxious. It's not like you're putting up, like, I don't know. Car ads or anything. It's fine. Yeah. [00:35:43] James: Yeah. And, and the, the, the one bombers, like if they didn't have internet, couldn't refresh their status, then they just wouldn't get the promos, but all of their data is saved. Right. So that's one cool part about my app that I really liked is that let's say you install the app today and you don't unlock pro mode for a month and you do 30 rides. All that data is there. I just keep it in the database. I just don't show it to you. [00:36:06] Frank: That's good. I guess that brings up the obvious thing too. Don't delete the data. I guess when that expiration happens, it is the transitions that are going to always be the hardest part. Like getting them to like click the buy button. That's okay. That's a marketing thing, but from an app, um, logic perspective, it's going from false to true and true to false. So you got to handle both scenarios, very smartly and tests. All the conditions like for me, I'm concerned about, they have a circuit open, it's using some advanced elements that only come in the pro version because that circuit just shut down, you know, does the circuit close? What does the simulation do? You know? It's, it's, it gets tricky, but I think, um, that's kind of an edge case. I think apps it's a little bit, uh, it should be an easier trend. [00:36:54] James: Yeah. And I only check that status when the app comes alive, like on appearing, whenever, you know, Xamarin forms, her iOS called the on a pairing. So I think it's on resume. So if a user, for example, subscribe to this and that purchase and the subscription. For one month and they kept the app open indefinitely, then they would indefinitely have this thing. I could be smarter. Right. I could be like, whenever you start a new ride, check the status, make sure it's a thing. Like I could do that too, but people don't leave apps open for one month. Fingers crossed, knock on wood. Um, some people do, but if it goes to the background and foreground is going to check that stuff again, I think that's good. Yep. [00:37:34] Frank: Absolutely agree. Uh, so I would say, just be aware of that interaction, but with open URL handlers too, because those things get called at the most random and awkward and annoying times. So just be careful about popping up anything automagically in that case too, something a mistake I always make now. [00:37:54] James: Oh, there's a, now I believe that I believe the implementation details at that point. Complete now I have, of course complicated my scenario because I already have a pro version, but we'll get to that in a little bit, but I'm, that's the app code, the actual app logic. Once I figured out how I was going to do it by, I created a method that was called add subscriptions. And it just took in a date. It was an extension method. It took a daytime and it, and it added it. So I, everywhere in the app, I just, you know, knew how to check the date, set the date, do all the things. And it was really easy. Um, from a logic standpoint, Any other questions before I get to testing Frank, which is the worst part you thought that was bad? [00:38:41] Frank: No, I know how bad the testing is. Like, cause I've gone through it with Kalka. So I do have a vague notion of how bad things are about to get here. I'm trying to think if there is anything left, but no, I think we covered most of the bases. Um, do you have a separate purchase dialogue versus your update and manage your subscription dialogue? Are they separate? Our view, [00:39:03] James: whatever page now they're the same. They're all. They're basically, basically what I have today is I changed the verbiage of pro to say lifetime pro, um, upgrade and then monthly pro subscription because I got emails. That I, there was a pro purchased and people like, is that monthly or is it a subscription or is it a lifetime? And I was like, oh, that's lifetime. So I made it very clear lifetime subscription. Got it. You know, I might even [00:39:30] Frank: put the word one time. Yeah. Make it very clear. [00:39:33] James: Got very clear one-time purchase. Yeah. You know, I think if I had just put that on my app, I think I probably would get more purchases of that anyways, but there's that, um, [00:39:42] Frank: you do have that one consumable still on there. [00:39:46] James: I do have the one, uh, pro upgrade one-time purchase in there. We'll talk about pricing non-consumable non-consumable yes. Yeah. Okay. [00:39:56] Frank: Oh, right. Okay. So now let me remind myself how testing goes. You log into app store connect and you create a bunch of. Users, which is a weird process. And then you have to do this on a device because I don't remember, does the simulator work or not either way the simulator doesn't work for anything anymore. So on device, you have to have a test device log out of all your I clued stuff and login using these new fake apple accounts. And after that everything's rosy right. Just work. [00:40:32] James: That is one option. And that's what I would have liked to do. However, I cannot get my app to deploy with my developers certificates on any of my devices for some reason. Um, so what I decided to do Frank was ship it to test flight and test it in the test flight sandbox mechanism, which. [00:40:52] Frank: Sorry, this is new to me. So this is a whole separate mechanism from the other one. [00:40:57] James: Yeah. So the one that you're describing is I plug my iPhone into my Mac or windows machine. I deploy with my certs and I then log into my sandbox account. It'll pop it up because it knows I'm in developer mode. And then it will basically it'll enable me to buy it with that sandbox mode. Now, if you put this in test flight, Directly anybody in test flight can make a purchase, but it's a fake purchase. Okay. Now, for your normal [00:41:28] Frank: iCloud account, you're using your James iCloud [00:41:31] James: account. And this was actually to my advantage because I didn't want to log out on my phone on every single account everywhere. I just wanted to use my normal account. And these are, these are fake purchases. Um, but they will show up in receipts. So. Uh, you don't have to pay for anything. So if you have TestFlight users, they can upgrade to pro or whatever it is, they don't have to pay for anything, but it's fake, but they'll test the functionality. It's the same as the sandbox account. If you're plugging it into your device, um, there now the one-time purchase is relatively easy because you either purchase it or you don't purchase it. Um, but with what you want to test in subscriptions is did I purchase the subscription? Um, and what happens if it expires and what happens if, um, if I've renewed it and what happens if I don't renew it, [00:42:21] Frank: what's about to happen. You had one day or like one minute subscriptions. Can you do a one minute pay per minute? [00:42:28] James: So this is really funky because now Frank, I've not only, I've not only already had my one-time purchase, that enables a functionality. So if I wanted to do a recent. I would, I needed to blank that out, but I've also hard-coded Hey, I bought this thing and in my app, I say, please add one month, five days. So check again in one month, five days. So what I had to do was I actually went and I said, add five minutes to the subscription because Frank on the ultimate guide to subscriptions, to iOS from a revenue cap, which is the best blog that I've ever had in my entire life that I will absolutely link to because it's the absolute. IOS subscription testing blog ever. This individual writes, Hey, your app store subscription. One month apple is going to set these sandbox duration to five minutes and in five minutes they will auto renew it. Is it two months? They're going to give you 10 minutes. Is it three months, 15 minutes, six months, 30 minutes. One year, one hour. I feel [00:43:35] Frank: like I'm just like so old and out of. You know, like, of course it's all built into Tesla and of course they accelerate time to make testing easier. They never did this for us back in the day, but it's so nice that they're doing it now. Honestly, I'm, I'm only a little bit angry that we never had this in the beginning, but I'm relieved, hugely relieved that it's actually improved this much. Yeah. [00:44:00] James: So I have one month subscription, five minutes now, apple. Automatically renew that subscription, regardless if the app is installed, if it's open, if anything, up to 12 times, they're not gonna tell you how many times. Ah, but up to 12 times, [00:44:19] Frank: Yep. Interesting. So, um, in your Apatow, uh, you calculate the expiry date yourself, right? Yes. So now there's going to be a conflict between the one you calculate in the app. Well, one, [00:44:31] James: so what I did to test this was I changed that instead of my one extension method. And this is why I made it a one extension method that every daytime calls to add time to itself. So I said, well, I know it's five minutes. So what I'm going to do is. Um, said it's a five minutes. So in my app in test flight, it's a little dangerous, but I said me testing it. I said only add five minutes of the subscription. Additionally, Frank, we, you and I have talked about this before. But I actually created a separate screen, a debug screen that will output in descending order every in every in-app purchase. And it'll also tell me information about like, when my app thinks it's going to expire and when the most Regent recent purchase was, and I can get to that. Anybody could, if they tap on a label 20 times in the application to get to it. Cause I was like, I need to debug this in real time. So this is like, it's really kind of crazy. And I did that and. I put in the five minutes and sure enough, the majority, not all the majority of my logic totally worked Frank. Like it just worked like out of the box and apple kept giving me more, more receipts and more receipts and more receipts. And sure enough, my descending order, you know, by transaction date and grabbing the first. Totally worked at, which makes sense because it's like, we'll get grimy their latest one. And that, that should be the one that I add time to, to see if it gets expired or not. Now I did make one mistake and this is what's really funny is since I'm testing and test flight, if I have a bug, Frank, I can't. I need to like, do a whole new build and a whole new push new install. I messed up a little bit in my app, which is when I did that. Pop-up after the expiration to refresh the status, I forgot to add the method that says refresh the status. Like I just, I forgot to call the method that I wrote. So, um, I was in there. And after the first one, I was like, okay, I got 50 minutes right at, at max who knows the minimum, but I got I'm like, I got 15 minutes. Right. So I go in and I fix my code. I kick off an app center that takes 12 minutes. I ship it and I'm waiting and I'm refreshing and I'm refreshing, refreshing. And after like five minutes, it shows up in test flight. I'm like refresh test flight and I install. And within the one hour sandbox, I not only tested the functionality, I fixed this stuff, got a new built and tested the new stuff as well. And it totally worked, which is kind of amazing. [00:47:08] Frank: Bravo, Bravo, uh, yeah, per per the last episode, I've also been abusing test flight late. It's Apple's fault and they let us, of course, we're going to do it. Um, I dunno, like it still sounds better than uploading to my device and, um, doing the crazy iCloud test accounts. I don't know, they both sound a little bit bad, but. I have set up CD and everything. I imagine I'm going to be testing it the exact same way you are. I might put like a debug console in or something, especially in like something like salmon forms, just put a list, view throat, some array of anything at that list view, and just render it out. [00:47:49] James: I like that idea. Yeah. Yeah. And I also say according to this document, the, those upgrades downgrades scenarios. They say that they're not supported in sandbox now. I don't know if that means it's not support on test flight, but they, like they say, you got to test this in production, which [00:48:08] Frank: are wonderful. [00:48:09] James: And also receipts, receipts are not available in the sandbox. Like the purchase is made or something it's always wacky, like yeah. Yeah. These things it's super weird just in general. So. Here's [00:48:23] Frank: what I'm going to have to do. Sorry. I'm still going back to my problem of, I have, um, uh, people who paid for the app full price, and I want to help them along. Um, I should put in the detection code for that into a release where I'm not making any other changes and just test out that detection code for a little while first. Yeah. Yeah. [00:48:42] James: And then work from. Yeah. And then the other thing that I thought about too, and you and I had a great conversation about it was, well, how do you actually make those users feel pretty good about their previous purchases and things like that? So what I'm going to do my plan is to actually increase the lifetime subscription, which is what they all got. They already purchase already to, uh, uh, probably double the price. Right. And then I'm going to introduce the new price and the in-app subscription at the same time. But of course, if they already bought in, they basically got 50% off of the lifetime. So they should feel pretty good that they got it. Right. So what you could do is I do detect [00:49:28] Frank: that. Yeah. Yeah. Yeah. So you got to put a cute little emoji what'd you do. Yeah. Yeah, pretty much. Yep. Thanks for being [00:49:36] James: awesome. And blah, blah, blah. Right. So they all, they already know it. Like you can detect to say, okay, is this the first time they opened the application and they're not a pro or they're not a pro user, or they are a pro user and they've opened it before. And you could add a Boolean to see if you need to like open that prompt or whatever. So. Overall, like one of these [00:49:55] Frank: bullions increases that test matrix. What are we up to? Three, four. That's a lot of horsepower things you got to test. [00:50:04] James: It's a lot of booleans now that being said. I did spend a lot of time testing it. And, uh, also I, that's only on iOS. I still need to test that on Android, which I think is even more know, probably similarly as complicated there. And the setup is very similar, but again, I'm maybe now happy and. 80%, 75%, because I'm not doing the account validation, cancellation, all that other stuff. But like I said, you know, it's one month. So if they gave me for a month, then that's fine, you know? Yeah. Whatever. Yeah. [00:50:39] Frank: And honestly, I, in the beginning, Pretty adamant in my head that I would offer a yearly to just as a courtesy. But now that I'm thinking about the implementation details, Nope, one month you're right James, one month, that's the way to go. [00:50:55] James: My thought has been this, which is, um, right now, if I can get. My, my hope is this. My hope is that I introduced the in-app subscriptions and some people try a month out or two months or a year out, whatever, however they want to go where maybe they didn't want to do the full-time price. Cause I'm going to introduce this thing at, I think I'm going to introduce it at 99 cents with the option. If nobody buys. Put it down to 49 cents. Cause you can always go down. You probably shouldn't go up. That's my assumption because I don't know how that happens once. Is it like, are they, are they grandfathered into that old pricing? So my plan is 99 cents, which means after four months, if they subscribe, I'll have made the same money as if they upgraded a pro I, um, I'm sorry. [00:51:43] Frank: Sorry. I w we got to rewind there. So if they're on an auto renew and you up the price, what happened? [00:51:49] James: I don't know. Yeah. [00:51:51] Frank: Okay. [00:51:53] James: Yeah. I don't know, think through your [00:51:54] Frank: pricing before, [00:51:55] James: so think of your pricing and I think I'm going to do 99 cents. First. I feel like that feels fine. And then if no one's buying it, I'll just make it 49 cents. I can always go down now for the in-app purchase. The single time I've adjusted that I've moved it up and I moved it down. It's you know, whatever that doesn't matter. Just refreshes. So not to be. Oh, that's, [00:52:18] Frank: what's kind of nice about app prices too, is even after you've bought it, apple, doesn't show you the price anymore. It's kind of funny. They've done that since the beginning. And so you're kind of free to change [00:52:27] James: the price. Yeah. It was just a super good thing. Yeah. So at this point in my mind, I'm feeling pretty good about those gone I'm pretty much done is on it. Yeah. I do want. Put it out in the world. I need to get it through apple testing, of course. But besides that, I just I'm smoothing it over. I'm rechecking my logic, making sure it's a month. Things like that. Now what I did, which was fun is that. I actually went and of course all the five minutes subscriptions stopped right there, all done. So what I did is I re enabled the one month, five days flag in my app did a new build. Now at this point, I can restore purchases and make sure that it's adding one month, five days again. Right? So you hit that restore option. It's kind of going to override that five minute time. So that's an option. Like you can put these different matrixes in there basically. And, um, and do that stuff, but yeah, it's a complicated process. [00:53:30] Frank: Yeah. Um, I feel like you have at well in hand, I feel like it's going to work out. Um, I, I don't hear any flaws in your design. [00:53:41] James: I have faith. I'm feeling pretty good about it. I'm feeling pretty good about it now. Um, [00:53:45] Frank: you said you haven't done any, uh, app store review yet. Have you done external testing on test flight? [00:53:53] James: Um, just to myself [00:53:55] Frank: external though, not internal, [00:53:57] James: uh, to Heather, I have Heather tested on her phone, [00:54:00] Frank: external, like it's the thing. It's a difference. Internal versus external flight now? No. No. Okay. So you haven't gone through a review. [00:54:09] James: No. Now I have, though, I will tell you this much. I, for my skiing app, I did put in a subscription purchase, but I didn't do all this stuff about like auto renewing and all this other stuff, because I didn't care. There's no functionality. It was a tip jar. You know what I mean? Got it. So I just kind of was like, whatever. And. Um, that one did get rejected multiple times because when you put enough subscriptions into your app, which are different than purchases, you have to link to the terms of service from apple or your own in the app and on the app store description. Oh, in both places. So be aware of [00:54:49] Frank: that little detail. Yeah. [00:54:51] James: Thanks. Yeah, so they, they rejected my app and then I added a link to the app in the app as a terms of service. And it just, I literally linked to the apple thing. They said it was ours. It works great. And then they rejected it again. They said, you also have to put it into your description. I was like, Where like, oh, why my app store? Why, why [00:55:11] Frank: can't they do [00:55:12] James: that? That's how I know. Well, it's funny. Cause they said or use the predefined field and I was like, there is no predefined field. There's one for privacy policy, but that's. Oh, I it's weird. [00:55:23] Frank: Yeah. I guess if you were to ask me just randomly, I would have guessed there was a field, but I don't know. I was guessing. Hmm. [00:55:28] James: Maybe there is, I can't find it. So if you find it, let me know it's in there. So that was the one. Gotcha. With us. I've had an app officially released into the app store when with an app subscriptions and it totally works fine and there was approved and it was in the store. So it's again, Bravo, [00:55:47] Frank: Bravo. But not this one. You're talking about the old one, right? [00:55:52] James: This is the skiing app that one's in there, but the cadence, the bike cadence app, where I have the check every month to all that stuff that. Hopefully by the time this week, it'll be out into the app store. So [00:56:04] Frank: exciting. Very exciting. We've been talking about this for a while. Um, I was a little bit nervous, but I feel like you, you walked us through it nicely, James. Thank you. This all seems very doable. Um, I do need to go read a whole bunch of docs on receipt validation, just to bring my current knowledge up to date. And then there was something else, a little bit scary you mentioned in there, but I've totally forgotten already. So we'll just never talk about it [00:56:31] James: again. And I go and we'll do a whole episode on receipt validations. Once one of us fully understand it. All right. Well, I think that's going to do it for this week's podcast. Again, thanks to magic mind, uh, for helping us out. You know, like I said, this little drink has been absolutely delicious, making me more productive and getting more stuff done and drinking it side by side my coffee. So I'll do the same stuff in the morning. It's delicious. Give it a try. Go to magic mind.co/merge and get 20% off your first order at. 20 in the coupon code section at checkout. And again, it is a fully money-back guarantee. So give it a try and let us know what you think of it I've been digging it. So it was Frank. So it was either. So until next time, I'm James Monson Magno and I'm Frank Krueger. [00:57:14] Frank: Thanks for listening.