Creating a paid R SaaS with Firebase, Paddle and Shiny
Create a template for R users to create paid subscription services for Shiny Apps.
An example is deployed to shinyapps.io here:
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.
Many thanks to...
This project is derived from:
- 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
Steps to have working demo bootstrap
- 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
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
- Deploy the Cloud Function in
payment_app/fb_functionsin the same Firebase project via the GCP console. This handles communication between Firebase and Paddle webhooks. You can do this via
gcloud functions deployif you have
gcloudinstalled 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:PORTto test locally (
http://127.0.0.1:PORTdoesn't work with Firebase login) - I launch Shiny in Viewer pane then visit
http://localhostin my browser
- Deploy the test Shiny app in
shiny/with the client auth key and
.Renvironin the same folder
- See the
global.Rfor 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, Firestore
usePaddle()is placed at the top of pages you want to use Paddle in, and loads the Paddle JS library
pdle_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
Running the payment app
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.