A product offer is an additional sales opportunity that's displayed to customers before or after they complete checkout. This guide introduces pre-purchase product offers, and post-purchase product offers, and describes the available resources that you can use to build product offers in Shopify checkout.

## How it works

You can build functionality in your app that enables merchants to provide the following experiences:

- [Pre-purchase product offers](#pre-purchase-product-offers)
- [Post-purchase product offers](#post-purchase-product-offers)

## Pre-purchase product offers




> Shopify Plus:
> [Checkout UI extensions](/docs/api/checkout-ui-extensions) that render on the information and shipping and payment steps in checkout are available only to stores on a [Shopify Plus](https://www.shopify.com/plus) plan.






A pre-purchase product offer is an additional sales opportunity that's displayed to customers before they complete checkout.

You can use a [checkout UI extension](/docs/api/checkout-ui-extensions) to build a pre-purchase product offer. The following example shows a pre-purchase product offer that renders at the [`purchase.checkout.block.render`](/docs/api/checkout-ui-extensions/latest/apis/extensiontargets) target:

<video style="width: 100%; height: auto;" autoplay muted loop controls>
  <source src="/assets/apps/checkout/product-offer.webm" type="video/webm">
  <source src="/assets/apps/checkout/product-offer.mp4" type="video/mp4">




## Post-purchase product offers



> Beta:
> Post-purchase checkout extensions are in beta and can be used without restrictions in a [development store](/docs/api/development-stores). To use post-purchase extensions on a live store, you need to [request access](/docs/apps/build/checkout/product-offers/build-a-post-purchase-offer#step-5-request-access).






A post-purchase product offer is an additional sales opportunity that's displayed to customers immediately after they complete checkout.

The post-purchase page appears after the order is confirmed, but before the [**Thank you** page](/docs/apps/build/checkout/thank-you-order-status). You can use a [post-purchase extension](/docs/api/checkout-extensions/post-purchase) to add custom content such as the following:

| Example | Description  |
|---|---|
|  Upsell offers | Prompt a customer to add more products to their initial order after they've completed payment. |
|  Survey requests | Ask a customer to complete a survey after they've completed checkout. |
|  Feedback requests | Ask a customer to complete a feedback form after they've completed checkout.  |
|  Donation requests | Ask a customer to submit a donation after they've completed checkout. |
|  Discount code offers | Offer a customer additional discounts on products using a specific code. |
|  Loyalty sign-ups |  Ask a customer to join a rewards or points program. |
|  Important notifications | Offer additional information that's valuable to customers. |

The following is a basic example of a post-purchase checkout extension:

![A basic example of a post-purchase checkout extension](/assets/api/cross-sells/post-purchase-animation.gif)




### Customer flow

The following diagram illustrates a high-level customer flow for an app that uses a post-purchase checkout extension:

![Post-purchase flow diagram](/assets/api/cross-sells/post-purchase-flow.png)

1. The customer goes to the payment information page.

2. The page loads the [Checkout::PostPurchase::ShouldRender](/docs/api/checkout-extensions/post-purchase/api) extension point.

3. Optional: The extension makes a network call to your app server to obtain any data needed for the post-purchase page. The extension can store data in the browser's local storage, speeding up the time to the first render.

4. The extension returns the result of `render` to the payment information page. For `render` to be `true`, all the required conditions must be met. For example, the customer's credit card must be vaulted before the post-purchase offer is displayed.

5. The customer completes checkout.

6. If render returns `true`, then the post-purchase page loads the [Checkout::PostPurchase::Render](/docs/api/checkout-extensions/post-purchase/api) extension point. Any stored data is directly available to the `render` extension point. You app needs to call [`done`](/docs/api/checkout-extensions/post-purchase/api#postpurchaserenderapi) to redirect the customer to the **Order status** page.

### Checkout extensions

Post-purchase checkout extensions use a technology that hosts your extension on Shopify's CDN and integrates directly into the Shopify checkout. It includes a set of [consistent UI components, targets, and development tools](/docs/api/checkout-extensions).

You create an extension by writing in Vanilla JS or React, and deciding whether to use TypeScript. Shopify securely hosts and renders your user interface in the client. When the extension appears to the customer in the checkout, it includes both app-provided and Shopify-provided interface elements, as shown in the following diagram:

![Post-purchase checkout app extension framework diagram](/assets/api/cross-sells/app-extension-framework-post-purchase.png)

### Limitations and considerations

The following limitations and considerations for post-purchase checkout extensions apply:

| Area  | Context  |
|---|---|
| Payment provider | Third-party payment providers that require the customer’s CVN/CVV to be retained aren't supported. This might include, but isn't limited to, payment providers such as Braintree, Payflow Pro, PayPal Payments Pro, and Eway. |
| Additional payment methods  |  The post-purchase page won't be surfaced in the following scenarios: <ul><li>The customer chooses to check out with an installment service or a wallet service (such as Klarna, Affirm, AfterPay, Apple Pay, Amazon Pay, or Google Pay).</li><li>The initial purchase was made with a gift card or any payment method other than a credit card.</li></ul> |
| Purchase events  |  Third-party analytic services that use the Shopify Pixel API (such as Google Analytics, Facebook, Pinterest and Snap) report only the purchase event and value for the initial purchase. |
|  Analytics | Third-party analytics services that use the [`ScriptTag`](/docs/api/admin-graphql/latest/objects/ScriptTag) object or [additional scripts](https://help.shopify.com/manual/orders/status-tracking/customize-order-status#add-additional-scripts) have incomplete conversion data, because they're only triggered on the **Order status** page.  |
|  Duties and support for multiple currencies | Post-purchase upsell offers won’t be surfaced on orders with duties and multiple currencies.  |
|  Order creation delays | In scenarios such as flash sales where the Shopify Platform is under extreme load, our system might optimize to capture orders but briefly delay the order creation step for a fast and seamless buyer experience. In these scenarios, post-purchase pages won't be surfaced, even if the request for the post-purchase page was properly made.  |
|  Multiple apps | Merchants with multiple apps that have the post-purchase checkout extension need to select which app appears on the post-purchase page. You can use a banner during app onboarding to let merchants know that they can [select your app](/docs/apps/build/checkout/product-offers/ux-for-post-purchase-product-offers#post-purchase-app-selector) as the default post-purchase app in the Shopify admin checkout settings.  |
| Fulfillment holds  | Shopify places a hold on fulfillment for all orders undergoing a post purchase cross-sell flow. Holds are released either when the customer visits the **Order status** page, or after a set amount of time, if the customer doesn't complete the post-purchase flow. <br></br>If the customer doesn't complete the flow (for example, the customer closes the browser before actioning the post-purchase upsell offer), then the fulfillment hold is lifted one hour after submission of the initial checkout. Fulfillment holds are only supported using the [`FulfillmentOrder`](/docs/api/admin-graphql/latest/objects/fulfillmentorder) resource.  |
|  Interaction with the **Order status** page |  The post-purchase page shouldn't be used as a replacement for the **Order status** page. For more information, refer to the [customer flow](/docs/apps/build/checkout/product-offers#post-purchase-product-offers#how-it-works). |
| API versioning  | The post-purchase checkout extension APIs aren't versioned and don't follow the [Shopify API versioning](/docs/api/usage/versioning) quarterly release schedule.  |
|  Orders without a shipping address | If the customer's checkout results in the creation of an order without a shipping address, then you can't add a subscription to the order using post-purchase. For example, a customer might have bought only digital products, which doesn't require a shipping address. <br></br>Similarly, a customer might choose local pickup as their delivery method, which also doesn't require a shipping address. You can determine in advance whether a shipping address exists by viewing the payment step within the `ShouldRender` extension point. If the `destinationCountryCode` input field is `null`, then no shipping address is set.  |
|  Orders for local delivery | Post-purchase upsell offers won’t be surfaced on orders for local delivery.  |
| Minimum order price | Orders need to be $0.50 or more to qualify for post-purchase offers. |
|  Accepted offers | A customer can accept a maximum of three post-purchase offers for each checkout.  |
| Number of post-purchase pages  |  You can create only one post-purchase page. However, because a post-purchase extension is a single-page app, you can paginate the single page to create multiple pages. |
| Sales channel | Orders need to be placed through the Online Store sales channel to qualify for post-purchase upsells. Other sales channels won't render post-purchase upsell pages. |
| Storage API with Shop Pay | When buyers check out using Shop Pay, the `Render` extension target can't read data that's stored in the <a href="/docs/api/checkout-extensions/post-purchase/api#storage">Storage API</a> during the `ShouldRender` extension target. This is because the targets are running in different domains (`shop.app` and the merchant's domain). |

## Getting started

Follow these tutorials to get started with building pre-purchase and post-purchase experiences.

<div class="resource-card-grid">
  <div>
  <a class="resource-card" href="/docs/apps/build/checkout/product-offers/build-a-pre-purchase-offer" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/growth"
     data-alt-src="/assets/resource-cards/growth-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Build a pre-purchase product offer checkout extension
    </h3>
    <p class="resource-card__description">Build a pre-purchase upsell offer that prompts the customer to add a product to their order.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/apps/build/checkout/product-offers/build-a-post-purchase-offer" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/globe"
     data-alt-src="/assets/resource-cards/globe-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Build a post-purchase product offer checkout extension
    </h3>
    <p class="resource-card__description">Create a basic example of a post-purchase checkout extension.</p>
  </a>
</div>

</div>


## Developer tools and resources

Explore the following developer tools and resources to get familiar with building pre-purchase and post-purchase experiences.

### Pre-purchase



<div class="resource-card-grid">
  <div>
  <a class="resource-card" href="/docs/api/checkout-ui-extensions/latest/extension-targets-overview" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/build"
     data-alt-src="/assets/resource-cards/build-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Checkout UI extensions API reference
    </h3>
    <p class="resource-card__description">Consult the API reference for checkout UI targets and their respective types.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/api/checkout-ui-extensions/latest/components" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/blocks"
     data-alt-src="/assets/resource-cards/blocks-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Components for checkout UI extensions
    </h3>
    <p class="resource-card__description">Learn about the components that are available in checkout UI extensions.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/api/checkout-ui-extensions/latest/configuration" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/gear"
     data-alt-src="/assets/resource-cards/gear-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Checkout extension configuration
    </h3>
    <p class="resource-card__description">Learn about the properties that you can configure in your checkout UI extension.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/apps/build/checkout/product-offers/ux-for-pre-purchase-product-offers" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/heart"
     data-alt-src="/assets/resource-cards/heart-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      UX for pre-purchase product offers
    </h3>
    <p class="resource-card__description">Explore UX guidelines that you can refer to when building pre-purchase product offers.</p>
  </a>
</div>

</div>





### Post-purchase



<div class="resource-card-grid">
  <div>
  <a class="resource-card" href="/docs/api/checkout-extensions/post-purchase/api" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/build"
     data-alt-src="/assets/resource-cards/build-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Post-purchase extension points API
    </h3>
    <p class="resource-card__description">Consult the API reference for post-purchase extension points and their respective types.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/api/checkout-extensions/post-purchase/components" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/blocks"
     data-alt-src="/assets/resource-cards/blocks-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Components for post-purchase extensions
    </h3>
    <p class="resource-card__description">Learn about the components that are available in post-purchase extensions.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/api/checkout-extensions/post-purchase/configuration" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/gear"
     data-alt-src="/assets/resource-cards/gear-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      Post-purchase extensions configuration
    </h3>
    <p class="resource-card__description">Learn about the properties that you can configure in your post-purchase checkout extension.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/api/checkout-extensions/post-purchase/jwt-specification" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/utility"
     data-alt-src="/assets/resource-cards/utility-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      JWT specification
    </h3>
    <p class="resource-card__description">Learn how JWTs need to be structured in order to be used in post-purchase checkout extensions.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/apps/build/checkout/product-offers/ux-for-post-purchase-product-offers" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/heart"
     data-alt-src="/assets/resource-cards/heart-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      UX for post-purchase product offers
    </h3>
    <p class="resource-card__description">Explore UX guidelines for post-purchase upsells.</p>
  </a>
</div>

<div>
  <a class="resource-card" href="/docs/apps/build/checkout/product-offers/ux-for-post-purchase-subscriptions" data-theme-mode="">
    <div class="resource-card__indicator-container"><img
     src="/assets/resource-cards/heart"
     data-alt-src="/assets/resource-cards/heart-dark"
     aria-hidden="true"
     class="resource-card__icon themed-image"></div>
    <h3 class="resource-card__title">
      UX for post-purchase subscriptions
    </h3>
    <p class="resource-card__description">Explore UX guidelines for post-purchase subscriptions.</p>
  </a>
</div>

</div>