Docs Guides Create a Shopify app with Mantle x Gadget

Integrate your Gadget-hosted Shopify app with Mantle

1. Create your Shopify app on Gadget

Head over to gadget.dev and create your Shopify app.

In order to use the Shopify Billing API, apps must have a public distribution setting. Go to your Shopify partner dashboard, select your app, select the Choose Distribution button and then select Public distribution.

2. Add the app to Mantle

In your Mantle dashboard, under Apps hit the Add app button to add this new app. Once added, go to Settings for the app and create a new API key.

Add the app ID and API key to GADGET_PUBLIC_MANTLE_APP_ID and MANTLE_API_KEY variables in Gadget Settings -> Environment Variables. We’re using GADGET_PUBLIC_ in front of the app ID environment variable because we want it available on the frontend, do not use this in front the of the API key since it should be kept secret.

3. Add Mantle package

In Gadget, open package.json and add @heymantle/polaris to the dependency list:

"@heymantle/polaris": "^12"

This includes @heymantle/react and @heymantle/client as dependencies.

Once you’ve added the Mantle dependency, select Run yarn to update dependencies in Gadget.

4. Add mantleApiToken to the shopifyShop model

In Gadget, under API/models/shopifyShop/schema, hit the plus button to add a string field called mantleApiToken.

5. Identify shops to Mantle when they install the app

First, add a helper file API/services/mantle.js:

import { MantleClient } from "@heymantle/client";

const mantleClient = new MantleClient({
  appId: process.env.GADGET_PUBLIC_MANTLE_APP_ID,
  apiKey: process.env.MANTLE_API_KEY,
});

const identifyShop = async ({ shop, api }) => {
  const { id, name, email, myshopifyDomain, accessToken } = shop;
  const result = await mantleClient.identify({
    platform: 'shopify',
    platformId: id,
    myshopifyDomain,
    accessToken,
    name,
    email,
  });
  await api.internal.shopifyShop.update(shop.id, {
    shopifyShop: {
      mantleApiToken: result.apiToken
    },
  });
};

module.exports = {
  identifyShop,
  mantleClient,
};

Now, under API/models/shopifyShop/actions for each file install.js, reinstall.js, update.js we want to identify the shop to Mantle:

import { identifyShop } from '../../../services/mantle'

// replace onSuccess with this
export async function onSuccess({ params, record, logger, api, connections }) {
  await identifyShop({
    shop: record,
    api,
  });
};

Shops will now be identified to Mantle and you’ll have the Mantle customer API token that you can use in frontend requests.

6. Add MantleProvider context to your frontend

Next, we’ll need to add the MantleProvider context to your react frontend to be able to access mantle customer information and performance actions such as subscribe. In WEB/components/App.jsx you’ll need to load the current authenticated shopifyShop object in the Embedded components to get the Mantle customer API token mantleApiToken from that object. With this you’ll surround the returned components in Embedded ith MantleProvider and include the appropriate props:

import { MantleProvider } from "@heymantle/react";
import { useFindFirst } from "@gadgetinc/react";

// ......

function EmbeddedApp() {
  const [{ data, fetching }] = useFindFirst(api.shopifyShop);

  if (fetching) {
    return (
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          height: "100%",
          width: "100%",
        }}
      >
        <Spinner accessibilityLabel="Spinner example" size="large" />
      </div>
    );
  }

  return (
    <MantleProvider
      appId={process.env.GADGET_PUBLIC_MANTLE_APP_ID}
      customerApiToken={data?.mantleApiToken}
    >
      <Outlet />
      <NavMenu>
        <Link to="/" rel="home">Shop Information</Link>
        <Link to="/about">About</Link>
      </NavMenu>
    </MantleProvider>
  );
}

7. Add plans page

Next you’ll want to add a couple plans so there’s something to show on this page, hop on back to your Mantle dashboard, select your test app you created in Step 2, under Plans hit the Add plan button and add a couple test plans.

Now, to show these plans to your customers in your app, add a new file WEB/routes/plans.jsx

import { Page, Layout } from "@shopify/polaris";
import { TitleBar } from "@shopify/app-bridge-react";
import { useNavigate } from "react-router-dom";
import { useMantle } from '@heymantle/react';
import { PlanCardStack, PlanCardType } from '@heymantle/polaris';

export default function () {
  const navigate = useNavigate();

  const { customer, plans, subscribe } = useMantle();

  return (
    <Page
      title="Plans"
      backAction={{
        content: "Shop Information",
        onAction: () => navigate("/"),
      }}
    >
      <TitleBar title="Select a plan" />
      <Layout>
        <Layout.Section>
          <PlanCardStack
            cardType={PlanCardType.Highlighted}
            customer={customer}
            plans={plans}
            onSelectPlan={async ({ plan, discount }) => {
              const subscription = await subscribe({ planId: plan.id, discountId: discount?.id, returnUrl: '/plans' });
              if (subscription.error) {
                console.error('Unable to subscribe: ', subscription.error);
              } else {
                open(subscription.confirmationUrl, "_top");
              }
            }}
          />
        </Layout.Section>
      </Layout>
    </Page>
  );
}

You’ll also need to add the route in App.jsx

import PlansPage from "../routes/plans";

// in function App()
<Route path="/plans" element={<PlansPage />} />

// in NavMenu
<Link to="/plans">Plans</Link>

Wrapping it up

That’s it! You now have a Gadget-hosted Shopify app with Mantle integrated, and a plans page. As always, reach out to us if you have any questions!