Create a custom storefront with Shopify Checkout and Recharge

A custom Shopify storefront separates the customer-facing experience from the backend platform infrastructure, offering more flexibility and freedom to create a completely unique experience for customers.

Before you start

It’s important to note creating a custom storefront requires factoring in the ongoing maintenance costs and developer resources to maintain it. See Demystifying headless commerce and The benefits of headless ecommerce for more information to determine if an API-driven approach is right for your store.

This guide walk you through the Shopify GraphQL Storefront API queries necessary to create a headless experience with Recharge-specific examples. This tutorial highlights extracting relevant data to this workflow, and provides context for how Shopify selling plans correspond to Recharge subscriptions.

Prerequisites

  • Shopify enables merchants to implement a headless storefront using their GraphQL Storefront API. Before diving in, we recommend checking out Getting Started with the Storefront API if you're unfamiliar with this API.
  • Create product in Shopify, then add subscription rules for those product in Recharge. See Creating subscription rules for details.

Retrieve product and identify Shopify subscription properties

Use the Shopify GraphQL API to retrieve the Recharge subscription options for a product. Once you have the subscription type, discounts, and frequencies for the product, you will display the information to customers using your own product display page. Examples of this can include a standard subscription widget, an upsell option on the cart page, or a subscription element in a unique quiz flow.

Recharge subscription properties

Each Recharge product contains the following three key subscription properties:

  • Subscription type: Subscription only, one-time and subscription, or prepaid
  • Discount settings: The discount percentage applied to the subscription option (not applicable to subscription-only type)
  • Order schedule: The frequency at which each subscription order process

Shopify selling plans

To sell Recharge subscriptions on your Shopify store, Recharge creates selling plans in Shopify that reflect the Recharge subscription properties described above. Shopify includes detailed information about selling plans
in their documentation. See Query selling plans for a product. Below is a brief overview:

  • Selling plans: How a product can be sold and purchased. Recharge creates a new selling plan for each subscription rule.
  • Selling plan IDs: The unique identifier for each selling plan that is used to tie a cart line item to the associated selling plan when adding a subscription to the cart.
  • Selling plan groups: Containers for the selling plans that represent a selling method like subscribe and save. Recharge creates one selling plan group for each product.
  • Price adjustments: Discount, if any, applied to products purchased as a subscription.

Query Shopify GraphQL API

To find Recharge subscription properties, query the Shopify GraphQL API. See the example below, which retrieves a test product with three variants in Shopify and the following subscription rules in Recharge:

  • Subscription type: One-time and subscription
  • Discount settings: 10%
  • Order schedule: 1, 2, and 3 months

For more detailed information on selling plans and managing subscriptions using the Storefront API, refer to Manage subscription products on storefronts.

Storefront API query:
POST /api/2021-07/graphql.json

  productByHandle(handle:"sour-gummy-bears") {
    id
    variants(first: 5) {
        edges {
            node {
                id
                title
                priceV2 {
                amount
                currencyCode
                }
            }
        }
    }
    requiresSellingPlan
    sellingPlanGroups(first: 1) {
        edges {
        node {
            name
            options {
                name
                values
            }
            sellingPlans(first: 10) {
            edges {
                node {
                id
                name
                description
                recurringDeliveries
                priceAdjustments {
                    orderCount
                    adjustmentValue {
                    __typename
                    ... on SellingPlanPercentagePriceAdjustment {
                        adjustmentPercentage
                    }
                    ... on SellingPlanFixedAmountPriceAdjustment {
                        adjustmentAmount {
                        amount
                        currencyCode
                        }
                    }
                    ... on SellingPlanFixedPriceAdjustment {
                        price {
                        amount
                        currencyCode
                        }
                        }
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
}

Response

    "data": {
        "productByHandle": {
            "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzY3NDEzMjkyNDg0NjU=",
            "variants": {
                "edges": [
                    {
                        "node": {
                            "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC80MDUwNzk2ODcxNzAwOQ==",
                            "title": "Small",
                            "priceV2": {
                                "amount": "4.0",
                                "currencyCode": "USD"
                            }
                        }
                    },
                    {
                        "node": {
                            "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC80MDUwNzk2ODc0OTc3Nw==",
                            "title": "Medium",
                            "priceV2": {
                                "amount": "8.0",
                                "currencyCode": "USD"
                            }
                        }
                    },
                    {
                        "node": {
                            "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC80MDUwNzk2ODc4MjU0NQ==",
                            "title": "Large",
                            "priceV2": {
                                "amount": "10.0",
                                "currencyCode": "USD"
                            }
                        }
                    }
                ]
            },
            "requiresSellingPlan": false,
            "sellingPlanGroups": {
                "edges": [
                    {
                        "node": {
                            "name": "Sour Gummy Bears",
                            "options": [
                                {
                                    "name": "1 Month(s), 2 Month(s), 3 Month(s)",
                                    "values": [
                                        "1 Month(s)",
                                        "2 Month(s)",
                                        "3 Month(s)"
                                    ]
                                }
                            ],
                            "sellingPlans": {
                                "edges": [
                                    {
                                        "node": {
                                            "id": "Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi80ODI0NDM0NzM=",
                                            "name": "Delivery every 1 Month",
                                            "description": null,
                                            "recurringDeliveries": true,
                                            "priceAdjustments": [
                                                {
                                                    "orderCount": null,
                                                    "adjustmentValue": {
                                                        "__typename": "SellingPlanPercentagePriceAdjustment",
                                                        "adjustmentPercentage": 10
                                                    }
                                                }
                                            ]
                                        }
                                    },
                                    {
                                        "node": {
                                            "id": "Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi81NTc4NzU0MDk=",
                                            "name": "Delivery every 2 Months",
                                            "description": null,
                                            "recurringDeliveries": true,
                                            "priceAdjustments": [
                                                {
                                                    "orderCount": null,
                                                    "adjustmentValue": {
                                                        "__typename": "SellingPlanPercentagePriceAdjustment",
                                                        "adjustmentPercentage": 10
                                                    }
                                                }
                                            ]
                                        }
                                    },
                                    {
                                        "node": {
                                            "id": "Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi81NTc5MDgxNzc=",
                                            "name": "Delivery every 3 Months",
                                            "description": null,
                                            "recurringDeliveries": true,
                                            "priceAdjustments": [
                                                {
                                                    "orderCount": null,
                                                    "adjustmentValue": {
                                                        "__typename": "SellingPlanPercentagePriceAdjustment",
                                                        "adjustmentPercentage": 10
                                                    }
                                                }
                                            ]
                                        }
                                    }
                                ]
                            }
                        }
                    }
                ]
            }
        }
    }
}

Extract the Recharge subscription type, discount settings, and order schedule from the response using the following properties:

  1. Subscription type: To determine the subscription type, look for:
  • requiresSellingPlan: true for subscription-only and prepaid subscriptions. false for one-time and subscriptions.
    • In this example, this is false because the product can be purchased both as a one-time (without a selling plan) or as a subscription (with a selling plan).
  • sellingPlans name property: To differentiate between subscription-only and prepaid.
    • Subscription-only and one-time and subscription will include the delivery frequency only. Ex: “Delivery every 1 month”
  • Prepaid subscriptions will have both a delivery and charge frequency. Ex: “Delivery every 1 month, Charge every 3 months”
  1. Discount settings: To determine the discount percentage, reference the adjustmentPercentage (within the priceAdjustments object) for the selling plan.
  • In this example, it is set to 10.
  • To render the subscription price, you can take the variant price * (100 - adjustmentPercentage)/100
  1. Order schedule: To determine the order schedule, reference the values listed in the sellingPlanGroups options. Note that prepaid subscriptions will only list the actual delivery frequency. The charge frequency can be found in the selling plan name.
  • This example has "1 Month(s)", "2 Month(s)", "3 Month(s)", which correspond to three selling plans with the following selling plan IDs (note that these are the Storefront API Base64 encoded strings and differ from the admin IDs):
    • Delivery every 1 month: Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi80ODI0NDM0NzM=
    • Delivery every 2 months: Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi81NTc4NzU0MDk=
    • Delivery every 3 months: Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi81NTc5MDgxNzc=

Create a cart

The next step is creating a cart with a Recharge subscription line item using the information you retrieved in the previous step. In order to add a subscription item to the cart, you’ll need the:

  • Quantity
  • Merchandise ID (variant ID)
  • Selling plan ID

🚧

Note

Shopify’s checkout workflow does not currently support subscriptions, so it’s not possible to create a checkout directly with the Shopify Storefront API. You’ll need to use the cart workflow to create a cart with the subscription line items and generate a link to the checkout. See Manage a Cart with the Storefront API for details.

In this example the customer selects the large variant as a monthly subscription. Call the cartCreate mutation and input the corresponding variant/merchandise ID and the selling plan ID:

POST https://{shop_id}.myshopify.com/api/2022-01/graphql.json

mutation {
  cartCreate(input: {
    lines: [
      {
        quantity: 1,
        merchandiseId: "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC80MDUwNzk2ODc4MjU0NQ==",
        sellingPlanId: "Z2lkOi8vc2hvcGlmeS9TZWxsaW5nUGxhbi80ODI0NDM0NzM="
      }
    ]
  }) {
    cart {
      id
      createdAt
      updatedAt
      lines(first:10) {
        edges {
          node {
            id
            merchandise {
              ... on ProductVariant {
                id
              }
            }
          }
        }

      }
      attributes {
        key
        value
      }
      estimatedCost {
        totalAmount {
          amount
          currencyCode
        }
        subtotalAmount {
          amount
          currencyCode
        }
        totalTaxAmount {
          amount
          currencyCode
        }
        totalDutyAmount {
          amount
          currencyCode
        }
      }
    }
  }
}

Response:

    "data": {
        "cartCreate": {
            "cart": {
                "id": "Z2lkOi8vc2hvcGlmeS9DYXJ0LzRkMTE2OGQ2N2JlNzRhNzdiNTQyZDgzNDBjOGI5MGNj",
                "createdAt": "2021-11-19T04:46:30Z",
                "updatedAt": "2021-11-19T04:46:30Z",
                "lines": {
                    "edges": [
                        {
                            "node": {
                                "id": "Z2lkOi8vc2hvcGlmeS9DYXJ0TGluZS9jYWY3YzE3Y2NjMGY1YjcyN2Q5MDUzMGM4YzFiOTc2OD9jYXJ0PTRkMTE2OGQ2N2JlNzRhNzdiNTQyZDgzNDBjOGI5MGNj",
                                "merchandise": {
                                    "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC80MDUwNzk2ODc4MjU0NQ=="
                                }
                            }
                        }
                    ]
                },
                "attributes": [],
                "estimatedCost": {
                    "totalAmount": {
                        "amount": "9.85",
                        "currencyCode": "USD"
                    },
                    "subtotalAmount": {
                        "amount": "9.0",
                        "currencyCode": "USD"
                    },
                    "totalTaxAmount": {
                        "amount": "0.85",
                        "currencyCode": "USD"
                    },
                    "totalDutyAmount": null
                }
            }
        }
    }
}

You can see the large variant was added to the cart with the discounted price of $9 (10% off $10). For more information on managing the cart, see Manage a cart with the Storefront API.

Create a checkout

Next, generate the checkout URL and redirect the customer to the pre-populated checkout. To generate a checkout URL, pass the cart ID from the create cart response into the following query:

  cart(id: "Z2lkOi8vc2hvcGlmeS9DYXJ0LzRkMTE2OGQ2N2JlNzRhNzdiNTQyZDgzNDBjOGI5MGNj") {
    checkoutUrl
  }
}```
**Response:**
```{
    "data": {
        "cart": {
            "checkoutUrl": "https://rachels-sci-onboarding.myshopify.com/cart/c/4d1168d67be74a77b542d8340c8b90cc"
        }
    }
}

When you navigate to the URL in the response, you’ll see the corresponding selling plan name pre-populated in the order summary:

Once the checkout is completed, the subscription will be created in both Shopify and Recharge.

Post-purchase

Lastly, it’s important to determine how customers will manage their subscriptions post-purchase. With the standard Recharge Shopify integration, Recharge adds a Manage Subscriptions link to the Shopify customer accounts section that redirects customers to their unique Recharge customer portal. Depending on the configured customer portal settings, the portal will either be embedded within the Shopify storefront or hosted by Recharge. For more information on the Recharge customer portal options, see Understanding the customer portal.

There are several options for managing the post-purchase experience using a custom storefront:

Use Shopify’s account login, account pages, and the standard Recharge customer portal flow

Simply leverage the Shopify hosted login and account pages rather than incorporating them into your custom store. This option does not require backend APIs. You can use Shopify’s standard account creation and login flow to enable customers to log in to their accounts and access their customer portal. To add the Recharge customer portal redirect link to the account page, add the following code to the desired location in the customer/accounts.liquid file:

<p><a href="/tools/recurring/login/">Manage Subscriptions</a></p>

When a user clicks on this link, Recharge will authenticate the user based on their Shopify login status and redirect them to the customer portal subscriptions page. You can specify whether you want to embed the portal within a Shopify storefront or host it via Recharge in the customer portal settings. Merchants using the Recharge hosted portal and on the Recharge Pro plan can also set up a custom customer portal domain.

Embed the Recharge customer portal in a headless customer account page using the Storefront API and the Recharge API

Another option is to handle the login and account flow outside of Shopify and embed the Recharge portal into your store. Use the Recharge JS SDK to generate a customer portal link.

Create a custom API-based portal

The most complex yet flexible option is to create your own customer portal using the Recharge API. This method uses Recharge's robust API endpoints to create a completely customized portal that is optimized for specific customer needs. For more information, see Building a custom customer portal with the Recharge API.


Need Help? Contact Us