How to set up your local development environment with Apple Pay and Stripe

By Zach Caceres and Meron Yemane

The Context

At Curology, we want to make it as convenient as possible for users to navigate our checkout flow.

In the past few years, many popular browsers have added support for new browser APIs that help users share a preferred payment method during checkout.

In the iOS ecosystem, this new UI flow is called Apple Pay. Users checking out on a mobile or desktop Safari browser can click an Apple Pay button that looks like this:

This button opens a native browser UI which allows the user to confirm their payment.

Apple Pay and similar “Payment Method API” integrations are a great way to lower friction during checkout. With Apple Pay, users don’t need to enter their credit card or address. They just click the button, confirm the purchase, and off they go.

The Problem

Payment processors like Stripe have excellent support for Apple Pay. However, Apple makes local development pretty difficult.

Apple imposes two requirements for developers to access the Apple Pay UI flow:

  1. The website’s URL must be served from a secure (HTTPS) context
  2. The developer must prove ownership of the domain they’re using by hosting a special file (often called the “well-known” file) and registering it with Apple

These aren’t a big deal for a website in production—any competent tech team will serve their product over HTTPS and it’s trivial to host a file. But it’s not as easy during the development process.

Most web developers code locally using a simple HTTP server on localhost. Apple Pay does not support this. To even see the Apple Pay button in Safari, you must serve your application via HTTPS and register it as an owned domain with Apple.

These local servers are not public (nor HTTPS) by default. If you try to register a server like localhost:8080 with Apple’s verification service, it won’t work. We need an easy way to share a local server with the public Internet, using a consistent domain that we register with Apple.

The Setup

Thankfully, tools like Expose from the exist. We can use Expose to make our local development server a consistent domain served over HTTPS. We chose Expose because we use a Laravel (PHP) and React stack for our product. Other stacks could use tools like, which provide a similar experience.

  1. First, install Expose as a global composer dependency composer global require beyondcode/expose
  2. Creating an account with
  3. Retrieve your authentication token from the BeyondCode Expose account UI and add it to your Expose config file. You can add it by running: expose token YOUR-AUTH-TOKEN
  4. Serve your web app on localhost as normal. In the following steps we’ll assume you’re serving from localhost:8080
  5. In your terminal, run expose share localhost:8080 --subdomain=your-preferred-subdomain-here. Expose will print a new HTTPS url to the terminal. Copy this value.
  6. You may have to do step 4 twice if you need to serve both the backend and frontend of your application. For example, if your backend is served on localhost:8080 and your webpack server runs on localhost:3000, do step 4 for both of these. If you don’t, you’ll end up with mixed-content errors since only part of the app is served over HTTPS. Save the URLs that Expose provides.
  7. Within your application’s .env file and any other areas where URLs may be hardcoded, replace localhost URLs with their replacements from Expose. For example, http://localhost:8080 might become
  8. Time to register your frontend application with Apple! Thankfully, Stripe provides a simple endpoint to do this. Replace the sample values and then run this in your terminal: curl <; \\ -u "YOUR STRIPE LIVE KEY GOES HERE": \\ -d domain_name="YOUR SUBDOMAIN FROM EXPOSE GOES HERE"

Let’s recap. During these steps we:

  • Set up Expose
  • Served our application locally
  • Received an HTTPS URL from Expose
  • Registered that URL with Apple

Once this is done, you’re ready to develop locally with Apple Pay!


Sending large streams of data over the wire can overwhelm Expose. Curology has a large front-end codebase of internal tools and customer-facing applications. Consider code-splitting your front-end applications and serving only the bundles you need via webpack. We were able to trim out megabytes of Javascript by selectively serving the apps that hold Apple Pay, rather than the entire front-end codebase.

Expose also provides a configurable PHP file at ~/.expose/config.php. This file provides many opportunities for optimization. For larger sites, I recommend bumping up the Expose process memory_limit to 1024M . You can also lower the max_logged_requests value if you find your Expose server is running out of memory. Finally, you can wrap the Expose process into a bash script like this one:

        #!/usr/bin/env bash

expose share localhost:3000 --subdomain=my-backend-server & expose share localhost:8080 --subdomain=my-frontend-assets


At Curology, we’re constantly looking for ways to improve our developer workflow, and replicating realistic production scenarios in our local environment is an important part of that. Setting up our local environment with Apple Pay and Stripe required some workarounds, but ultimately allowed us to efficiently and effectively implement a valuable feature for our users. Hopefully you find it helpful as well. Thanks for reading!

Join us

We believe great skin should be a fact of life, not a luxury

View open positions