We're using Firebase Analytics to track our Android app.
We've connected it to our Google Play account in hopes to receive the automatic in_app_purchase events. What we later realized is that does not support in-app subscriptions: https://support.google.com/firebase/answer/6317485?hl=en
How do we track subscription revenue events?
We thought about using the ecommerce_purchase event (https://support.google.com/firebase/answer/6317499?hl=en) so we could track the ARPU, ARPPU and LTV of our users.
The problem we are facing is dealing with subscription recurrence. Should we manually send this event each month/year and stop sending once the subscription is cancelled? It seems like a error-prone hack ...
Any other ideas?
Thanks!
If you want to pursue the technique you described, from your server, you can track whether a google subscription event is active or cancelled via the subscriptions API.
If you poll this API, you should be able to determine when to send the ecommerce_purchase event to firebase.
Here is a ruby example of polling the API for Google Play. You can poll the iTunes API with a similar technique.
supscriptions are a complex thing to measure and track in app, because the app might not get the cancel/change event and therefore continue tracking on something, that does not exist anymore. This leads to corrupt and untrustworthy data.
For that reason, we implemented it as follows:
client side:
We track all creation, changes and cancelations as custom events.
server side:
whenever we charge a subscription, we track this as a "purchase" event. Therefore, the calculated life-time-value of the user is correct and we still have a workflow of all the actions, changes, ... the user made.
I can really recommend this solution, because - even though it is slightly more complex - allows you to follow the full user journey, while having correct firebase stats at the same time.
Related
I started to implement Google Play Billing flow (Subscriptions only) for simple use cases but surprisingly there are quite limited articles showing how to do it in an optimal way. ClassyTaxi example (https://github.com/android/play-billing-samples/tree/3f34105c34e2ed2e88055ccf2b04088e8a5fd3a2/ClassyTaxiJava) is in my opinion over-complicated and mix some functions (e.g. acknowledging by Android app instead on back-end server).
Simple case:
App is built around Firebase services (Auth, Firestore, Cloud Functions, etc.)
Subscriptions are linked to the App user
Only one subscription type (Premium access), billed monthly or yearly
My billing flow for new purchases:
Android app starts BillingClient based on the subscription billing frequency chosen by the user
After successful payment processing, BillingClient sends a notification via RTDN/PubSub
Cloud Function processes that notification gets all Purchase data (Purchases.subscriptionsv2:get), verify it, stores in Firestore ("PurchasesCollection") with userId, and acknowledges
(Optional) Send FCM notification to all user devices about SubsctiptionState change
Android app listens "PurchasesCollection" to react to any Purchase change
With this approach, the Android app is just listening to Firestore changes and not making any Purchase processing activities as all of them are done on the server side.
In case of any Purchase changes (cancellations, pausing, expiring, etc.) Cloud Function will receive notification via RTDN and updates existing purchase, so the Android app will always get the most recent Subscription status and data.
Are there any drawbacks or security issues I didn't take into account?
In case the Android app just needs to confirm if a user is entitled to receive Premium access would it be sufficient to make a simple check expiryTime = Future (for at least one purchase from the list of all users' purchases)?
What is the most optimal and secure flow for this simple case?
We want to store when a google play purchase is refunded to a user for data analysis.
According to documentation, there are 3 ways for a user to request a refund for a subscription on google play:
https://support.google.com/googleplay/answer/2479637?hl=en
If the user requests the refund to the developer (us), we can keep track of it on our servers and manage it on our end, no problem. However, users can also ask google for a refund directly. Problem is that we can't find documentation on this kind of refunds.
Looking at the API documentation for subscriptions, it doesn't provide whether a purchase was refunded or not: https://developers.google.com/android-publisher/api-ref/purchases/subscriptions
Also tried looking into the realtime developer notifications system. Looks like it doesn't have an event for refunds.
https://developer.android.com/google/play/billing/realtime_developer_notifications#json_specification
Any idea what happens if google refunds a purchase on their end?
In my experience with the realtime events thus far, after a subscription is refunded two realtime-events get sent. First, a SUBSCRIPTION_CANCELED event is sent, followed by a SUBSCRIPTION_REVOKED event.
On my server, I treat the SUBSCRIPTION_CANCELED as a normal cancel, then if that event is followed by a SUBSCRIPTION_REVOKED event for the same subscription, I mark it as refunded.
Details can be found for these two specific events, as you also mentioned, at this link: https://developer.android.com/google/play/billing/realtime_developer_notifications.html#json_specification
Reading the documentation for subscriptions and related SO questions/answers i am still confused what to do when i have to stop providing the subscription services and content:
https://developer.android.com/google/play/billing/billing_subscriptions.html#cancellation
In all cases, you must continue to offer the content that your
subscribers have purchased through their subscriptions, as long any
user is able to access it.
For example i am offering some content via my server to subscribed users in my app. At one point i am unable to offer that content and i want to cancel all subscriptions?
The users theoretically wont be able to access the content any more and i certainly dont want to charge them for it any longer. The proper use case for me would be to cancel the user subscriptions and refund the remaining money for them. But i am not sure that this is acceptable according to the available information in the docs...i guess that i can do the cancellation and refunds using the google play developer API (still reading the available options) if that will cover the policy requirements somehow?
I am just finding it hard to believe that if a user for ex. rejects app updates and stays on an old app version with an old subscription i have to support him for eternity :) ?
I know what you are suffering the only way around this is communicate to your users to update. Usually this case would mean a FORCE UPDATE so when they open your app they have to update. Your backend has to have a service like that. If user doesn't update they can't use the app. Also I pretty much believe that some subscriptions are auto renewal so that's one the reasons why deleting in the play store is not possible. Also take into account that change price would generate almost the same problem. Since you can't change a price of a subscription at least the base price, the country price you can.
According to this
https://support.google.com/firebase/answer/6317485?hl=en
in_app_purchase event will be automatically tracked when a user completes an in-app purchase.
The problem occurs with test users.
They are not charged (since they are entered in "Test Accounts" list in google developer console) but in_app_purchase events are tracked for them too.
So, there are discrepancies between analytics and real payments.
Is there a way to separate somehow real and 'test' purchases?
Either, maybe a way to disable automatically tracking for certain events and send them manually? And how to recognize 'test' purchases in this case at runtime (in order to don't send in_app_purchase event)
I know it's a bit late, but putting down my 2-cents here:
I think you might already know that test purchases for Android in Firebase Analytics are accounted for, as mentioned here(see in_app_purchases), "Note: paid app-purchase revenue, subscription revenue (Android only), and refunds are not automatically tracked. Your reported revenue may differ from the values you see in the Google Play Developer Console. Events that are flagged as being invalid or as sandbox (test) are ignored. Only iOS events are flagged as sandbox".
That said, there isn't a way to recognize such purchases at runtime and avoid them from being reported for Android and populating your prod app data. However, there are only a couple of ways to deal with it currently(in my opinion):
Separate your prod data from test data: Look into this document on how to set up a separate app in Firebase to record your test data.
Disable collection of analytics for your test app: As shown here, you can temporarily or permanently disable collection of Firebase Analytics data. It includes the option to be able to disable and enable it at runtime.
Although, I would consider option #2 a little counter-intuitive given your case and go with #1 instead.
Disabling reporting of test purchase data to Analytics at runtime would require 2 things:
Knowledge of how the Google Play system recognizes a test purchase, what event is sent from the user device for such an event, and the ability to recognize/intercept that event.
The option of preventing an event from being reported to Firebase Analytics at runtime.
In this case, #2 definitely does not seem like an option currently. Hence, all we can do here is reach out to Firebase Support and request that feature. But until then, I don't see another way. But I'm curious and open to suggestions if somebody else has. :)
I'm writing an app that will support in-app subscriptions. The subscriptions will enable my users to use a number of services and benefits outside the Android world. I know that I can use Google Play Developer API to query the status of a subscription, but due to the nature of the offered services and benefits, it is not very convenient to do that. I was wondering if there is a way to get notified about the status of the subscription when it changes. Something like a web hook for example.
I wanted to post a comment in response to yours, but apparently this was too long. In addition to that, it is also kind of an answer to your question, so I thought this might be a good thing to just post it as an answer instead. Maybe it even solves your problem.
So, regarding your comment. You don't necessarily have to do it that way. Now, I don't know your system requirements, but I'll just share mine and hope it helps you out.
Save Users and Subscriptions on your server (database tables). Have a check_at column on the Subscriptions table, besides a renew_at one. Suppose the user has a monthly subscription created on the 1st of January. On that first day, you call your server from Android after the purchase is finished, save the subscription details, then set renew_at as February 1st and check_at as February 4th, considering you set 3 days as delay for transaction failure in Google Play Developer Console. This way, the user has time from 1st February to 3rd February to change credit card details if the payment fails on the 1st. Then on the 4th you will check the Google Play API for subscription details. But don't disable premium functionality during 1st-4th February. Disable it on the 4th if the subscription was canceled. This way, premium content is not delayed nor tampered with in any way. If the subscription end date returned by the API is in the future, then it was renewed, so you should keep premium activated. Now, how do you check it monthly on the 4th you may ask. Use some kind of scheduler to schedule tasks on the database.
This way you remove the need to rely on webhooks. Although I agree, webhooks would've been more efficient and probably even easier to implement.
Let me know if you have any questions or there are some flaws in the system I described.
Take a look at Real Time Notifications using Google Cloud's PubSub service. It sends notifications of payment/subscription events like: new buy, renewal, cancellation etc. It includes the token which can be used to retrieve additional info from the API like you do now.
You can also configure this PubSub Subscription to call a custom webhook (which still needs to query the PubSub) on each message that you receive.