DEV Community

Paul Asjes for Stripe

Posted on • Updated on

Building a Stripe App in 5 easy steps

During Sessions 2022 we announced Stripe Apps, the new way to extend Stripe.

If you haven’t already, you should watch the keynote and subsequent breakout session to understand why Stripe Apps was built, and what the future looks like for this new product.

In this post we’ll cover the very basics of getting started with building a Stripe App in just a few easy steps.

Pre-flight

You might already be familiar with the Stripe CLI. In case you aren’t, it’s a tool we built to help you integrate with Stripe as fast as possible. It has many features that can help you in building your integration, but we’re going to focus today on its use as the starting point for building your Stripe App.

As a prerequisite to this list, make sure you have the CLI installed and that you are using at least version 1.8.0 of the CLI.

1. Install the apps plugin

In your terminal, install the necessary apps plugin by running:

$ stripe plugin install apps

Check the CLI version and install the apps plugin

2. Create your app

Next, create your app with the command:

$ stripe apps create APP_NAME

Replacing APP_NAME with whatever you want to call your app. In the screenshot below I used example-app.

Create the app via the CLI

3. Provide your App ID and Display Name

The App ID is the unique ID associated with your app. These namespaces work similarly to package names in the NPM registry, in that they must be unique to prevent conflicts. This only matters if you’re planning on uploading your app later, so don’t worry too much if you are just testing things out for now.

Display name is the user facing name of your app that you’ll see in the Stripe dashboard. The CLI will try to guess a default value based on what you passed in.

If you’re having difficulty thinking of that perfect name (naming is hard!), don’t worry too much about it as both these values can be changed later.

Once naming is settled (or not, naming is still hard), the CLI will download and install all the necessary requirements for the app, create a new directory and initialise a new git repo.

4. Navigate to the new folder and run the app

Next, cd into the new directory and run:

$ stripe apps start

Start the app

Once you hit “enter” you’ll be prompted to pick a Stripe account to run your apps on. Once you’ve confirmed, you’ll be redirected to the dashboard where you’ll see your app appear in the side panel on the right.

The example app is specifically for the customer view screen

The boilerplate “Hello World” app defaults to the stripe.dashboard.customer.detail viewport, meaning that the app only does something when you navigate to a customer detail view. You could use this space to for instance display a list of “todo” items.

The example app, in all its glory

Many other viewports are supported.

5. See your changes reflected in the dashboard

Now that you have a basic app up and running, let’s make some changes to the code and see what happens. Open up /src/views/CustomerDetailView.tsx in your favourite IDE take a peek.

If you already know React, then this should hopefully look pretty familiar. As you might have inferred from the file suffix, Stripe Apps are written in TypeScript and React.


💡 Curious about how we built Stripe Apps? Make sure you join the Stripe Apps Q&A on June 2nd 2022!


The code you see is the example “Hello World” app you should see in your browser.

The ContextView component is the main viewpoint for your app and where your users will likely spend most of their time. It’s the area rendered to the right of the dashboard in its own side panel.

Let’s start fresh and remove everything inside the ContextView and the StyledLink component at the end. You should be left with something like this:



import {
  Box,
  ContextView,
  Divider,
  Icon,
  Link,
} from "@stripe/ui-extension-sdk/ui";

import type { ExtensionContextValue } from "@stripe/ui-extension-sdk/context";

/**
 * This is a view that is rendered in the Stripe dashboard's customer detail page.
 * In stripe-app.json, this view is configured with stripe.dashboard.customer.detail viewport.
 * You can add a new view by running "stripe apps add view" from the CLI.
 */
const CustomerDetailView = ({ userContext, environment }: ExtensionContextValue) => {
  return (
    <ContextView title="Your App">

    </ContextView>
  );
};

export default CustomerDetailView;


Enter fullscreen mode Exit fullscreen mode

Save the file and head back to your browser. You should see that the app has automatically updated and is now a rather boring white screen with just the “Your App” title.

Stripe Apps uses Hot Module Replacement, which means updates to your app’s code can be seen in the dashboard immediately without requiring a page refresh.

As you update your source code, you’ll see updates to your Stripe App’s interface immediately, without a page refresh

You might notice, however, that your app isn’t running on a localhost server, but right in the Stripe production Dashboard. This means that you have direct access to your test mode Stripe data whilst developing your app.

Whilst playing around with the code, you might notice that if you try to render a standard HTML node like a div, you get the error:

Unsupported component: div

Only components imported from the ui-extension-sdk can be used in Stripe Apps. This restriction serves two purposes:

  1. Security: This keeps both you and your users safe by limiting what can and can’t be done in the app sandbox. For example, an app can’t access sensitive data about a user’s Stripe account and a user can’t access an app’s secrets.
  2. Design cohesion: It ensures your app has the look and feel of the Stripe Dashboard.

Let’s improve on our boring screen and add a few lines of code that demonstrate using the components. We’re going to build a very simple app that shows how many times we’ve clicked a button, just to demonstrate how our components work together with familiar concepts like React hooks.



import {
  Box,
  Button,
  ContextView,
  Icon,
  Inline,
} from "@stripe/ui-extension-sdk/ui";

import type { ExtensionContextValue } from "@stripe/ui-extension-sdk/context";
import { useState } from "react";

/**
 * This is a view that is rendered in the Stripe dashboard's customer detail page.
 * In stripe-app.json, this view is configured with stripe.dashboard.customer.detail viewport.
 * You can add a new view by running "stripe apps add view" from the CLI.
 */
const CustomerDetailView = ({ userContext, environment }: ExtensionContextValue) => {

  const [timesClicked, setTimesClicked] = useState<number>(0);

  const incrementClick = () => {
    setTimesClicked(timesClicked + 1);
  };

  const clear = () => {
    setTimesClicked(0);
  };

  return (
    <ContextView title="Your App">
      <Box css={{
        layout: 'row',
        gap: 'small',
        alignX: 'center',
      }}>
        <Button type="primary" onPress={() => incrementClick()}>
          <Icon name="add"/>
          <Inline css={{ marginLeft: 'small' }}>Click me!</Inline>
        </Button>
        <Button onPress={() => clear()}>
          <Icon name="trash" />
          <Inline css={{ marginLeft: 'small' }}>Clear</Inline>
        </Button>
      </Box>
      <Box css={{
        padding: 'large',
        alignX: 'center',
        layout: 'row'
      }}>
        {`I've been clicked ${timesClicked} times!`}
      </Box>
    </ContextView>
  );
};

export default CustomerDetailView;


Enter fullscreen mode Exit fullscreen mode

Here we’ve added some new components, Box, Button, Icon and Inline.

Box and Inline can be considered similar to div and span in regular HTML in that that they are generic containers. They differ from other components in that they have access to the css prop, where you can pass in style options.

Button and Icon are fairly straightforward, the latter allows you access to a library of pre-designed icons.

Now save the file, switch to your browser and let’s see our app in action:

All the components together form this simple app

There we have a very simple app, built with the UI Extension SDK and React hooks!

In the next post, we’ll go into more complicated use cases like using the Stripe API from our app and incorporating a back end.

In the meanwhile, let us know what you’re working on or what you plan to build by staying in touch in these ways 👇

📣 Follow @StripeDev and our team on Twitter
📺 Subscribe to our Youtube channel
💬 Join the official Discord server
📧 Sign up for the Dev Digest

About the author

Paul Asjes

Paul Asjes is a Developer Advocate at Stripe where he writes, codes and hosts a monthly Q&A series talking to developers. Outside of work he enjoys brewing beer, making biltong and losing to his son in Mario Kart.

Top comments (0)