Skip to content

CHECK-384: Enable Google Pay support in Stripe PaymentSheet behind a feature gate - #2565

Open
tonyteate wants to merge 1 commit into
masterfrom
tony/check-384-google-pay-paymentsheet-init
Open

tonyteate wants to merge 1 commit into
masterfrom
tony/check-384-google-pay-paymentsheet-init

Conversation

@tonyteate

@tonyteate tonyteate commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

📲 What

  • Upgrade the Stripe Android SDK to 23.20.0.
  • Add Google Pay support to the existing Stripe PaymentSheet flow behind a Statsig feature gate.
  • Temporarily override Stripe’s GooglePayAvailabilityClient in non-production environments.
  • Re-wire the new PaymentSheet configuration into Crowdfund checkout, Late Pledge checkout, Payment Method Settings.

🤔 Why

  • Google Pay presents an opportunity to increase pledge conversion on Android by enabling backers to pledge with cards already saved to their Google Wallet, eliminating the friction of manually entering card details.

    This PR introduces Google Pay through the existing Stripe Payment Sheet integration within Crowdfund checkout, Late Pledge checkout, and Payment Method Settings.

  • A temporary override of GooglePayAvailabilityClient is included as a workaround for and from Stripe Android issue #13968, which is preventing the Google Pay integration from working reliably in the Test environment.

🛠 How

  • Bump the Stripe library to the latest version 23.20.0.
    • No code changes were required from this.
  • Extend Context.getPaymentSheetConfiguration() with optional Google Pay enablement and currency parameters for backwards compatibility.
  • Add Context.getGooglePayConfiguration() to build a nullable PaymentSheet.GooglePayConfiguration based on a boolean flag, optional currency code and the environment:
    • Return null when the gate is disabled, the currency is missing or blank.
    • Use the app's configured webEndpoint to set the Google Pay Test or Production Environment.
  • Add a new method isPaymentSheetGooglePayEnabled() containing the feature gate check into to PaymentMethodsViewModel, CrowdfundCheckoutViewModel, and LatePledgeCheckoutViewModel.
    • Follows an existing pattern for only checking the gate if configReady.
  • Derive the Google Pay currency from the associated Project in Crowdfund and Late Pledge checkout.
    • This currency is required for Google Pay to work with Setup Intents
    • For Payment Method Settings, the currency is hardcoded to USD as decided in the tech plan.
  • Add the Project currency to LatePledgeCheckoutUIState so it is available when Late Pledge configures PaymentSheet.
  • Add GooglePayAvailabilityUtil to isolate the temporary Stripe availability override.
    • This override removes the existingPaymentMethodRequired parameter from Google Pay readiness requests.
    • Install the override once in KSApplication.initApplication() for non-production environments as determined by ApiEndpoint, consistent with Dagger Stripe provider (ApplicationModule.provideStripe())
  • Add tests covering gate-on and gate-off behavior, nullable Google Pay configuration, blank currency handling, and Late Pledge Project currency propagation.

👀 See

Crowdfund Checkout

Screen_recording_20260924_201210.mp4

📋 QA

Feature gate - not passing

Note

The sandbox feature gate is set to pass when 'App Version >= 3.43.0'. Confirm internal_version_name < 3.43.0. This is, of course, the default state of the branch.

Prereqs:

  • Point the app to Staging
  • Log in

Payment Method Settings

  • Navigate to Settings > Account > Payment methods
  • Take note of the existing cards
  • Tap 'Add New Card'
  • Result:
    • The system presents the pre-existing payment sheet with just two options: Link, and manual card entry

Late Pledge Checkout

  • Navigate to a Late Pledge Project
    • E.g. Navigate to Search, set the 'Project Status' filter to 'Late pledge', tap 'See results', and click any Project that you haven't already pledged to.
  • Proceed through to the checkout screen
  • Tap 'New payment method'
  • Result:
    • The system presents the pre-existing payment sheet with just two options: Link, and manual card entry

Crowdfund Checkout

  • Navigate to a Live crowdfunding Project
  • Proceed through to the checkout screen
  • Tap 'New payment method'
  • Result:
    • The system presents the pre-existing payment sheet with just two options: Link, and manual card entry

Feature gate - passing

Note

The sandbox feature gate is set to pass when 'App Version >= 3.43.0'. Set internal_version_name >= 3.43.0 to pass the feature gate.

Prereqs:

  • Point the app to Staging
  • Log in

Payment Method Settings

  • Navigate to Settings > Account > Payment methods
  • Take note of the existing cards
  • Tap 'Add New Card'
  • Result:
    • The system presents a 'Select your payment method' bottom sheet with three options: '+ Add', 'Google Pay', and 'Link'
  • Tap the 'Google Pay' option
  • Result:
    • The system presents a native Google Pay bottom sheet with a default test card selected and, importantly, a label that says 'Your payment method won't be charged because you're in a test environment'.
  • Tap the default selected test card to open a full screen Wallet of test cards
  • Select any 'successful' card that has not already been added to your account, e.g. Visa **4242, Visa **5556, Mastercard **4444, or any other card prefixed with a country code.
  • Result:
    • The Google Pay bottom sheet is presented again displaying the selected card.
  • Tap the 'Pay' button in the Google Pay bottom sheet. Wait a few seconds while the selected card is setup through Stripe and Kickstarter's systems.
  • Result:
    • After a few seconds, the collection of payment methods is refreshes to include the selected card with the proper 'Card ending in' label and expiration.
  • Repeat the following steps:
    • Tap 'Add New Card'
    • Tap the 'Google Pay' option
    • Tap the default selected test card to open a full screen Wallet of test cards
  • Scroll down and select any 'failing'/'error' card. These should be listed below all of the 'successful' cards with country code prefixes, and should be prefixed by the issue e.g. Generic decline: Visa, Insufficient funds: Visa, Expired card: Visa, etc.
  • Tap the 'Pay' button in the Google Pay bottom sheet. Wait a few seconds while the selected card is setup through Stripe and Kickstarter's systems.
  • Result:
    • After a few seconds, the system presents an error Toast with the message 'Something went wrong'.
  • (To simplify the next QA step, you can remove new card added in this step).

Late Pledge Checkout

  • Navigate to a Late Pledge Project
    • E.g. Navigate to Search, set the 'Project Status' filter to 'Late pledge', tap 'See results', and click any Project that you haven't already pledged to.
  • Proceed through to the checkout screen
  • Tap 'New payment method'
  • Result:
    • The system presents a 'Select your payment method' bottom sheet with three options: '+ Add', 'Google Pay', and 'Link'
  • Tap the 'Google Pay' option
  • Result:
    • The system presents a native Google Pay bottom sheet with a default test card selected and, importantly, a label that says 'Your payment method won't be charged because you're in a test environment'.
  • Tap the default selected test card to open a full screen Wallet of test cards
  • Select any 'successful' card that has not already been added to your account, e.g. Visa **4242, Visa **5556, Mastercard **4444, or any other card prefixed with a country code.
  • Result:
    • The Google Pay bottom sheet is presented again displaying the selected card.
  • Tap the 'Pay' button in the Google Pay bottom sheet. Wait a few seconds while the selected card is setup through Stripe and Kickstarter's systems.
  • Result:
    • After a few seconds, the collection of payment methods is refreshes to include the selected card with the proper 'Card ending in' label and expiration.
  • Repeat the following steps:
    • Tap 'New payment method'
    • Tap the 'Google Pay' option
    • Tap the default selected test card to open a full screen Wallet of test cards
  • Scroll down and select any 'failing'/'error' card. These should be listed below all of the 'successful' cards with country code prefixes, and should be prefixed by the issue e.g. Generic decline: Visa, Insufficient funds: Visa, Expired card: Visa, etc.
  • Tap the 'Pay' button in the Google Pay bottom sheet. Wait a few seconds while the selected card is setup through Stripe and Kickstarter's systems.
  • Result:
    • After a few seconds, the system presents an error Toast.
  • Ensure the newly added card is selected, and complete the checkout by pledging to the project.
  • Result:
    • The system should complete the pledge successfully.

Crowdfund Checkout

  • Navigate to a Live crowdfunding Project
  • Proceed through to the checkout screen
  • Tap 'New payment method'
  • Result:
    • The system presents a 'Select your payment method' bottom sheet with three options: '+ Add', 'Google Pay', and 'Link'
  • Tap the 'Google Pay' option
  • Result:
    • The collection of Payment Methods in the app's Checkout screen includes a new item at the top with the label '**** Pay' and with a Google Pay icon.
    • The system presents a native Google Pay bottom sheet with a default test card selected and, importantly, a label that says 'Your payment method won't be charged because you're in a test environment'.
  • Tap the default selected test card to open a full screen Wallet of test cards
  • Select any 'successful' card that has not already been added to your account, e.g. Visa **4242, Visa **5556, Mastercard **4444, or any other card prefixed with a country code.
  • Result:
    • The Google Pay bottom sheet is presented again displaying the selected card.
  • Tap the 'Pay' button in the Google Pay bottom sheet. Wait a few seconds while the selected card is setup through Stripe and Kickstarter's systems.
  • Result:
    • After a few seconds, the full screen loading indicator is dismissed and no error toast message is displayed.
  • Repeat the following steps:
    • Tap 'New payment method'
    • Tap the 'Google Pay' option
    • Tap the default selected test card to open a full screen Wallet of test cards
  • Scroll down and select any 'failing'/'error' card. These should be listed below all of the 'successful' cards with country code prefixes, and should be prefixed by the issue e.g. Generic decline: Visa, Insufficient funds: Visa, Expired card: Visa, etc.
  • Tap the 'Pay' button in the Google Pay bottom sheet. Wait a few seconds while the selected card is setup through Stripe and Kickstarter's systems.
  • Result:
    • After a few seconds, the system presents an error Toast.
  • Ensure the newly added card is selected, and complete the checkout by pledging to the project.
  • Result:
    • The system should complete the pledge successfully.

Story 📖

@tonyteate tonyteate self-assigned this Sep 25, 2026
@tonyteate
tonyteate force-pushed the tony/check-384-google-pay-paymentsheet-init branch from 12f0e5f to 0b896e7 Compare September 25, 2026 00:35
@tonyteate
tonyteate requested a lite review from Copilot September 25, 2026 00:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Address the stale Late Pledge state capture and preserve the Rewards Selection refresh guard.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

Enables gated Google Pay support in Stripe PaymentSheet across checkout and payment settings, with a non-production Stripe workaround.

Changes:

  • Upgrades Stripe and adds Google Pay configuration.
  • Adds feature gating and currency propagation across payment flows.
  • Adds availability handling and unit tests.
File Summary
app/​src/​test/​java/​com/​kickstarter/​viewmodels/​PaymentMethodsViewModelTest.kt Tests Google Pay gate behavior.
app/​src/​test/​java/​com/​kickstarter/​viewmodels/​LatePledgeCheckoutViewModelTest.kt Tests gate behavior and currency propagation.
app/​src/​test/​java/​com/​kickstarter/​viewmodels/​CrowdfundCheckoutViewModelTest.kt Tests Google Pay gate behavior.
app/​src/​test/​java/​com/​kickstarter/​libs/​utils/​extensions/​ContextExtTest.kt Tests Google Pay configuration conditions.
app/​src/​main/​java/​com/​kickstarter/​viewmodels/​projectpage/​RewardsSelectionViewModel.kt Changes project-data refresh behavior; the existing refresh guard should be restored or preserved.
app/​src/​main/​java/​com/​kickstarter/​viewmodels/​projectpage/​LatePledgeCheckoutViewModel.kt Propagates project currency and evaluates the feature gate.
app/​src/​main/​java/​com/​kickstarter/​viewmodels/​projectpage/​CrowdfundCheckoutViewModel.kt Adds Google Pay feature-gate support.
app/​src/​main/​java/​com/​kickstarter/​viewmodels/​PaymentMethodsViewModel.kt Adds Google Pay feature-gate output.
app/​src/​main/​java/​com/​kickstarter/​utils/​GooglePayAvailabilityUtil.kt Adds the non-production Stripe availability workaround.
app/​src/​main/​java/​com/​kickstarter/​ui/​fragments/​CrowdfundCheckoutFragment.kt Configures gated Google Pay for crowdfund checkout.
app/​src/​main/​java/​com/​kickstarter/​ui/​activities/​ProjectPageActivity.kt Configures Google Pay for late pledges; the collector may use stale currency state.
app/​src/​main/​java/​com/​kickstarter/​ui/​activities/​PaymentMethodsSettingsActivity.kt Enables Google Pay in payment settings.
app/​src/​main/​java/​com/​kickstarter/​libs/​utils/​extensions/​ContextExt.kt Builds PaymentSheet Google Pay configuration.
app/​src/​main/​java/​com/​kickstarter/​libs/​featureflag/​StatsigClient.kt Defines the Google Pay feature gate.
app/​src/​main/​java/​com/​kickstarter/​KSApplication.kt Installs the environment-specific workaround.
app/​build.gradle Upgrades Stripe and adds the Wallet dependency.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

}

if (!refreshData) return
// if (!refreshData) return

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is technically a quick fix for the bug that nondeterministically prevents the rewards carousel from loading for Late Pledge Projects. I will create a separate PR for it at some point soon.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A legitimate fix now provided by #2566

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 30.76923% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.08%. Comparing base (a302985) to head (0b896e7).

Files with missing lines Patch % Lines
...com/kickstarter/utils/GooglePayAvailabilityUtil.kt 0.00% 11 Missing ⚠️
...om/kickstarter/libs/utils/extensions/ContextExt.kt 47.05% 7 Missing and 2 partials ⚠️
...wmodels/projectpage/LatePledgeCheckoutViewModel.kt 40.00% 0 Missing and 3 partials ⚠️
.../kickstarter/viewmodels/PaymentMethodsViewModel.kt 0.00% 0 Missing and 2 partials ⚠️
...ewmodels/projectpage/CrowdfundCheckoutViewModel.kt 0.00% 0 Missing and 2 partials ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #2565      +/-   ##
============================================
- Coverage     65.12%   65.08%   -0.05%     
- Complexity     2582     2594      +12     
============================================
  Files           409      410       +1     
  Lines         32996    33031      +35     
  Branches       4709     4713       +4     
============================================
+ Hits          21489    21498       +9     
- Misses         9046     9063      +17     
- Partials       2461     2470       +9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tonyteate
tonyteate marked this pull request as ready for review September 28, 2026 18:09
* Provides the configuration for the PaymentSheet, following the specs
* @see [link](https://stripe.com/docs/payments/accept-a-payment?platform=android&ui=elements#android-flowcontroller)
*
* @param googlePayCurrencyCode The three-letter ISO 4217 alphabetic currency code, e.g. "USD" or "EUR".

@Arkariang Arkariang Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth mentioning here the googlePayCurrencyCode is the merchant's ( Kickstarter ), not the project, took a moment to realize why on getGooglePayConfiguration "US" was hardcoded as country code and same with getPaymentSheetConfiguration "USD"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, I'll update the comments to add more clarification:

  • The countryCode set in the GooglePayConfiguration object is the country code of the business' (Kickstarter's) Stripe account, so that's hardcoded to "US". (Stripe docs, tech plan)
  • Noted in the PR details, the currencyCode for the GooglePayConfigurationObject is required for Setup Intents and should be set to the Project's currency. Only in Payment Method Settings, where there is no Project, it was decided to hardcode the value to "USD". Luke's comment here provides more context. So that's where you're seeing an explicit call to this.getPaymentSheetConfiguration(userEmail, googlePayEnabled, "USD") only in PaymentMethodSettingsActivity.flowControllerPresentPaymentOption(). On the other screens it's variable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, in a follow up message to Stripe reps, they responded today suggesting the countryCode may also need to be variable based on the Project (if I'm understanding their reply correctly). So if we need to make countryCode variable for Crowdfund & Late Pledge checkouts, I anticipate doing so in a separate PR but following the same pattern.

@Arkariang Arkariang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work tony!

Just confirming though one thing from an user perspective, are we ok with not showing the full label in this case? it just displays the word Pay with the asterics behind, there is the logo so the user definitely can differentiate the different payment options 🤔
Image

@tonyteate

Copy link
Copy Markdown
Contributor Author

Amazing work tony!

Thank you for reviewing! 💰

Just confirming though one thing from an user perspective, are we ok with not showing the full label in this case? it just displays the word Pay with the asterics behind, there is the logo so the user definitely can differentiate the different payment options 🤔

No, we are not ok with it 😄 We have a separate in-progress ticket for this label specifically ([CHECK-553]) so we can use the full label, check localization, or decide to use something else like 'GPay' and translate ourselves. Also double-checking the usage in e.g. the extension function StoredCard.isFromPaymentSheet(), but that looks fine.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants