Create a template for R users to create paid subscription services for Shiny Apps.
An example is deployed to shinyapps.io here:
https://mark.shinyapps.io/r-saas/
Login with one of the providers (more are available), use the coupon code "test123" to test the paid subscription service of Paddle. The paid content is a woeful plot.
This project is derived from:
- https://www.tychobra.com/posts/2019-01-03-firebasse-auth-wtih-shiny/
- Firebase AuthUI
- An early iteration inspired some of this package https://github.com/JohnCoene/firebase which it now uses for firebase auth
- Some guy on medium.com who did the cloud function in PHP but I can't find it now
- Firebase auth on login - select which services to support in Firebase UI
- Once you login but have not subscribed yet - Paddle creates a login button
- Paddle takes care of subscription and credit card details
- Subscription appears in Paddle UI
- If a paid subscriber already - see the great Shiny content
- User authentication and payment history kept in a Firebase Auth and Firestore
- Sync between Paddle and Firebase uses a Google Cloud Function in Python3.7
A diagram on how the app handles payments
- Download or clone this repository
- Create a Firebase account and setup as per https://firebase.john-coene.com/articles/get-started.html - get your firebase API key and project-id
- Create a Paddle account and setup and get your Paddle Vendor Id and create a test catalog subscription plan to get a Paddle Plan Id. Its helpful to also create a coupon with 100% discount for testing.
- Download a clientId JSON file for your GCP project (same as Firebase project), application type "Desktop app"
- Create env args via
.Renviron
or otherwise:
FIREBASE_API_KEY=your-api-key
FIREBASE_PROJECT=your-firebase-project
GAR_CLIENT_JSON=file-location-of-client-id
PADDLE_VENDOR=paddle-vendor-id
- When you create a Paddle subscription it gives you a productId - this should be unique for each Shiny app and is placed at the top of server.R in the
PADDLE_PRODUCT_ID
global arg. - Deploy the Cloud Function in
payment_app/fb_functions
in the same Firebase project via the GCP console. This handles communication between Firebase and Paddle webhooks. You can do this viagcloud functions deploy
if you havegcloud
installed or copy-paste into the web UI for Cloud Functions. - Create a firebase client auth key with "roles/datastore.viewer" role - with googleAuthR this can be done via:
library(googleAuthR)
# creates firebase-reader-auth-key.json file
gar_service_provision("firebase-reader", "roles/datastore.viewer")
- Run the Shiny app on
http://localhost:PORT
to test locally (http://127.0.0.1:PORT
doesn't work with Firebase login) - I launch Shiny in Viewer pane then visithttp://localhost
in my browser - Deploy the test Shiny app in
shiny/
with the client auth key and.Renviron
in the same folder - See the
global.R
for the payment functions that are used in the demo app, and you can adapt to your own use:
fb_document_get()
gets entries to the Firebase database, FirestoreusePaddle()
is placed at the top of pages you want to use Paddle in, and loads the Paddle JS librarypdle_subscribe()
creates a subscription button - you can select which product_id, user_id (the firebaseId is suggested), email to pre-populate in the form and the URL redirect that will be visited after payment
The Shiny App will offer to link to the payment popup via Paddle after login with Firebase Auth. The firebase auth ID is used to verify if the user has an existing subscription, and if not creates a payment button to do so. If a user does have a subscription, then they see the paid content.
If a subscription fails (the credit card is cacnelled or similar) then Paddle updates.
The Firebase databsae "subscriptions" is used to keep track of whether a user has paid or not. The communication between Firebase and PAddle is done via the Python cloud function in the payment_app/
folder - see its README for details.