Stripe offers two ways to provide discounts to your customers: Coupons and Promo Codes. While they’re related, they serve different purposes and are implemented differently.

Understanding Coupons vs Promo Codes

Coupons

  • Coupons are the underlying discount rules you create in Stripe.
  • They define the actual discount (e.g., 20% off, $10 off, etc).
  • They are not customer-facing and are identified by IDs in Stripe, that can either look like A1b2C3d4 or an ID chosen by you.
  • You can create coupons in your Stripe Dashboard.

Promo Codes

  • Promo codes are customer-facing codes that are linked to coupons.
  • They are what customers actually enter to get a discount.
  • They have a customer-friendly format (e.g., “BLACKFRIDAY50”), and they also have a unique ID generated by Stripe that looks like promo_1A2B3C4D5E6F7G8H9I0J.
  • You can create promo codes in your Stripe Dashboard from within a Coupon.

Both coupons and promo codes are environment-specific - they exist either in test mode or live mode in Stripe, but not both.

Make sure you’re using the correct mode for your Embeddable. If you want to test coupons or promo codes in both modes, you’ll need to create equivalent coupons and promo codes in both modes.

Implementing Promo Codes in Your Embeddable

There are two ways to implement promo codes in your Embeddable:

1. Manual Entry by Customer

To let customers enter their own promo codes:

1

Add Input and Button Components

  • Add a Container component to house your promo code components.
  • Add a 2nd Container component to display the input and button components side-by-side.
  • Add an Input Box component for use to enter the promo code, with a key such as new_promo_code.
  • Add a Button component for the user to click to submit the code.
  • Add 2 Plain Text components to display success + error messages, giving them the content of {{promo_code_success_message}} and {{promo_code_error_message}} respectively.
2

Style the components

  • Style the inner Container to use Flex to display the input and button components side-by-side, and consider giving it a max-width.
  • Style the input box to be a varying width, based on the width of the container.
  • Style the success message to be green, and the error message to be red.
3

Create an Action

Create an Action that will be triggered when the button is clicked:

function output(userData, { setUserData }) {
  // Get the promo code from the input, using its key
  const promoCode = userData.new_promo_code;
  
  // Apply the promo code using the Stripe Checkout function
  window.StripeCheckout.applyPromotionCode(promoCode)
    .then((result) => {
      if (result.type === 'success') {
        // On success:
        // - Update the success message to show the applied discount
        // - Clear any error message
        // - Reset the input box to empty
        setUserData({
          promo_code_success_message: `Promo code "${promoCode}" applied successfully!`,
          promo_code_error_message: "",
          new_promo_code: "",
        });
      } else {
        // Handle error case
        setUserData({
          promo_code_success_message: "",
          promo_code_error_message: result.error.message || "Invalid promo code",
        });
      }
    })
    .catch((error) => {
      // Handle any unexpected errors
      setUserData({
        promo_code_success_message: "",
        promo_code_error_message: "An unexpected error occurred",
      });
    });
}
4

Register User Data Keys

  • In your Embeddable settings, add the following keys to the “Registered Keys” section:
    • promo_code_success_message
    • promo_code_error_message
  • This ensures these keys are properly tracked and managed by the Embeddables reactive engine.
5

Add a Trigger to the Action

  • Add a Trigger to the Action that fires when the button is clicked.
6

Recommended: Reset Messages on Page Load

Since the Stripe checkout session is refreshed when the user refreshes or changes pages, you’ll want to reset the success and error messages when the page loads, to avoid the user thinking that their promo code is still applied.

  • Create a new Action to reset the success and error messages when the page loads.
function output(userData, { setUserData }) {
  setUserData({
    promo_code_success_message: "",
    promo_code_error_message: "",
  });
}
  • Add a Trigger to this Action that fires on page load.
  • This ensures the messages are cleared when the Stripe checkout session is refreshed.

2. Automatic Application

Use this method to automatically apply a promo code for all customers.

A UI for handling this without editing the JSON is coming soon!

In your Stripe component Options, open the JSON editor and add the following to the checkout session configuration:

{
  "checkout_session": {
    // ... other checkout session configuration ...
    "discounts": [  // Stripe currently only supports one object in the array
      {
        "promotion_code": "YOUR_PROMO_CODE_ID", // EITHER THIS
        "coupon": "YOUR_COUPON_ID"              // OR THIS
      }
    ]
  }
}

Tips:

  • Replace YOUR_PROMO_CODE_ID or YOUR_COUPON_ID with your actual promo code ID from Stripe.
  • Or, if you prefer, replace them with {{promo_code_id}} or {{coupon_id}} to use an ID calculated from a Computed Field or Action.
  • Make sure to remove either the promotion_code or coupon key, not both.
  • Make sure to remove all the comments (// ...) since JSON doesn’t support comments.
  • Make sure to remove the // ... other checkout session configuration ... line, since you’re only adding the discounts section.

When using automatic application, make sure you’re using the correct promo code for your environment (test vs live mode).

Troubleshooting

Best Practices

  1. Test Both Modes: Always test your promo codes in both test and live modes to ensure they work as expected.

  2. Clear Messaging: Make sure your UI clearly communicates:

    • Where to enter the promo code.
    • When a code has been successfully applied.
    • When a code is invalid and why.
    • That only one promo code can be applied at a time.
  3. Error Handling: Implement proper error handling in your Action to provide a good user experience when:

    • The code is invalid.
    • The code has expired.
    • The code doesn’t apply to the current products.
    • The code has already been applied.
  4. Security: Remember that promo codes are public-facing. Don’t include sensitive information in them, and consider implementing rate limiting if you’re concerned about brute force attempts.

  5. Data Management:

    • Register all user data keys in your Embeddable settings to ensure proper tracking and management.
    • Reset success/error messages on page load to handle Stripe checkout session refreshes.
    • Keep your user data structure clean by clearing input fields after successful code application.