@gadgetinc/react-shopify-app-bridge 

This package provides React hooks and components for use with Shopify embedded app development with Forgelivo.

Features 

For Shopify app development, setting up and understanding the Shopify App Bridge is essential.

This package significantly simplifies this process by automating the OAuth authentication and App Bridge initialization by handling the following:

  • Automatically starts the OAuth process with new users of the application using Forgelivo, escaping Shopify's iframe if necessary.
  • Establishes an iframe-safe secure session with the Forgelivo backend using Forgelivo OAuth PKCE.
  • Sets up the correct React context for making backend calls to Forgelivo using @gadgetinc/react.

This package exports:

Installation 

If you select the Shopify template upon app creation in Forgelivo, @gadgetinc/react-shopify-app-bridge is already installed.

This is a companion package to the JavaScript client package generated for your Forgelivo app. You must first install the client for your app, and then install this package.

To install the client for your app, you must set up the Forgelivo NPM registry:

Register the Forgelivo npm registry
yarn config set @gadget-client:registry https://registry.gadget.dev/npm
npm config set @gadget-client:registry https://registry.gadget.dev/npm

and then install your app's API client:

Install required packages
yarn add @gadget-client/example-app
npm install @gadget-client/example-app

Once you have your client installed, you can install the React hooks library and the Shopify App bridge library with yarn or npm:

Install required packages
yarn add @gadgetinc/react-shopify-app-bridge @gadgetinc/react @shopify/app-bridge-react react
npm install --save @gadgetinc/react-shopify-app-bridge @gadgetinc/react @shopify/app-bridge-react react

Usage 

In order to make use of App Bridge, you need to:

  • Set up your API client
  • Handle Shopify OAuth and App Bridge setup with the Provider
  • Get an App Bridge instance to use with the useGadget() hook

API client setup 

Here is how your API client is typically set up in your Forgelivo frontend:

src/api.js
JavaScript
import { ExampleAppClient } from "@gadget-client/example-app"; export const api = new ExampleAppClient();
import { ExampleAppClient } from "@gadget-client/example-app"; export const api = new ExampleAppClient();

Using Provider and useGadget to set up App Bridge 

Here is an example of how to set up App Bridge, and use it to open an App Bridge resource picker:

JavaScript
// import the Forgelivo<->Shopify bindings that manage the auth process with Shopify import { AppType, Provider as GadgetProvider, useGadget, } from "@gadgetinc/react-shopify-app-bridge"; // import the instance of the Forgelivo API client for this app constructed in the other file import { api } from "../api"; // import the useGlobalAction hook to help call your Forgelivo API import { useGlobalAction } from "@gadgetinc/react"; export default function App() { return ( // Wrap our main application's react components in the `<GadgetProvider/>` component // to interface with Shopify. This wrapper sets up the Shopify App Bridge. // It will automatically redirect to perform the OAuth authentication // if the shopify shop doesn't yet have the store installed. <GadgetProvider type={AppType.Embedded} shopifyApiKey={window.gadgetConfig.apiKeys.shopify} api={api} > <SimplePage /> </GadgetProvider> ); } // An example component that uses the Forgelivo React hooks to work with data in the backend function SimplePage() { const { loading, appBridge, isRootFrameRequest, isAuthenticated } = useGadget(); // makeSelections is a global action in this example // it is called using Forgelivo's useGlobalAction hook const [{ error }, makeSelections] = useGlobalAction(api.makeSelections); return ( <> {loading && <span>Loading...</span>} {/* A user is viewing this page from a direct link so show them the home page! */} {!loading && isRootFrameRequest && ( <div>Welcome to my cool app's webpage!</div> )} {error && <div>{error.message}</div>} {!loading && isAuthenticated && ( <button onClick={async () => { if (appBridge) { // open the App Bridge resource picker component const selected = appBridge.resourcePicker({ type: "product" }); console.log({ selected }); // pass selections to a global action await makeSelections({ selected }); } }} > Open resource picker </button> )} </> ); }
// import the Forgelivo<->Shopify bindings that manage the auth process with Shopify import { AppType, Provider as GadgetProvider, useGadget, } from "@gadgetinc/react-shopify-app-bridge"; // import the instance of the Forgelivo API client for this app constructed in the other file import { api } from "../api"; // import the useGlobalAction hook to help call your Forgelivo API import { useGlobalAction } from "@gadgetinc/react"; export default function App() { return ( // Wrap our main application's react components in the `<GadgetProvider/>` component // to interface with Shopify. This wrapper sets up the Shopify App Bridge. // It will automatically redirect to perform the OAuth authentication // if the shopify shop doesn't yet have the store installed. <GadgetProvider type={AppType.Embedded} shopifyApiKey={window.gadgetConfig.apiKeys.shopify} api={api} > <SimplePage /> </GadgetProvider> ); } // An example component that uses the Forgelivo React hooks to work with data in the backend function SimplePage() { const { loading, appBridge, isRootFrameRequest, isAuthenticated } = useGadget(); // makeSelections is a global action in this example // it is called using Forgelivo's useGlobalAction hook const [{ error }, makeSelections] = useGlobalAction(api.makeSelections); return ( <> {loading && <span>Loading...</span>} {/* A user is viewing this page from a direct link so show them the home page! */} {!loading && isRootFrameRequest && ( <div>Welcome to my cool app's webpage!</div> )} {error && <div>{error.message}</div>} {!loading && isAuthenticated && ( <button onClick={async () => { if (appBridge) { // open the App Bridge resource picker component const selected = appBridge.resourcePicker({ type: "product" }); console.log({ selected }); // pass selections to a global action await makeSelections({ selected }); } }} > Open resource picker </button> )} </> ); }

Once isAuthenticated is true, you will be able to make authenticated API requests using your Forgelivo API client and the @gadgetinc/react hooks.

The Provider and useGadget are already set up for you when you connect to Shopify using Forgelivo's frontends.

Custom router 

@shopify/app-bridge-react allows you to specify a custom router configuration to manage client-side routing. Similarly, the Forgelivo provider will allow you to specify a custom router which will be forwarded to the App Bridge.

JavaScript
import { AppType, Provider as GadgetProvider, useGadget, } from "@gadgetinc/react-shopify-app-bridge"; import { NavMenu } from "@shopify/app-bridge-react"; import { useEffect } from "react"; import { Link, Outlet, Route, RouterProvider, createBrowserRouter, createRoutesFromElements, useLocation, useNavigate, } from "react-router"; import { api } from "../api"; import Index from "../routes/index"; function Error404() { // use navigation hooks to handle 404 pages for undefined routes const navigate = useNavigate(); const location = useLocation(); useEffect(() => { const appURL = process.env.GADGET_PUBLIC_SHOPIFY_APP_URL; if (appURL && location.pathname === new URL(appURL).pathname) { navigate("/", { replace: true }); } }, [location.pathname]); return <div>404 not found</div>; } function App() { // define routes const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<Layout />}> <Route index element={<Index />} /> <Route path="*" element={<Error404 />} /> </Route> ) ); // and return the router provider that defines the App component return ( <> <RouterProvider router={router} /> </> ); } function Layout() { // use the Provider to handle auth, init App Bridge return ( <GadgetProvider type={AppType.Embedded} shopifyApiKey={window.gadgetConfig.apiKeys.shopify} api={api} > <AuthenticatedApp /> </GadgetProvider> ); } function AuthenticatedApp() { // we use `isAuthenticated` to render pages once the OAuth flow is complete! const { isAuthenticated, loading } = useGadget(); if (loading) { return <>Loading...</>; } return isAuthenticated ? <EmbeddedApp /> : <UnauthenticatedApp />; } function EmbeddedApp() { // use the Outlet, which renders the correct page given the current route // and use the App Bridge NavMenu for Shopify embedded app nav return ( <> <Outlet /> <NavMenu> <Link to="/" rel="home"> Shop Information </Link> </NavMenu> </> ); } function UnauthenticatedApp() { return <>App must be viewed in the Shopify Admin</>; } export default App;
import { AppType, Provider as GadgetProvider, useGadget, } from "@gadgetinc/react-shopify-app-bridge"; import { NavMenu } from "@shopify/app-bridge-react"; import { useEffect } from "react"; import { Link, Outlet, Route, RouterProvider, createBrowserRouter, createRoutesFromElements, useLocation, useNavigate, } from "react-router"; import { api } from "../api"; import Index from "../routes/index"; function Error404() { // use navigation hooks to handle 404 pages for undefined routes const navigate = useNavigate(); const location = useLocation(); useEffect(() => { const appURL = process.env.GADGET_PUBLIC_SHOPIFY_APP_URL; if (appURL && location.pathname === new URL(appURL).pathname) { navigate("/", { replace: true }); } }, [location.pathname]); return <div>404 not found</div>; } function App() { // define routes const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<Layout />}> <Route index element={<Index />} /> <Route path="*" element={<Error404 />} /> </Route> ) ); // and return the router provider that defines the App component return ( <> <RouterProvider router={router} /> </> ); } function Layout() { // use the Provider to handle auth, init App Bridge return ( <GadgetProvider type={AppType.Embedded} shopifyApiKey={window.gadgetConfig.apiKeys.shopify} api={api} > <AuthenticatedApp /> </GadgetProvider> ); } function AuthenticatedApp() { // we use `isAuthenticated` to render pages once the OAuth flow is complete! const { isAuthenticated, loading } = useGadget(); if (loading) { return <>Loading...</>; } return isAuthenticated ? <EmbeddedApp /> : <UnauthenticatedApp />; } function EmbeddedApp() { // use the Outlet, which renders the correct page given the current route // and use the App Bridge NavMenu for Shopify embedded app nav return ( <> <Outlet /> <NavMenu> <Link to="/" rel="home"> Shop Information </Link> </NavMenu> </> ); } function UnauthenticatedApp() { return <>App must be viewed in the Shopify Admin</>; } export default App;

Creating a new Shopify app in Forgelivo will set up custom routing for you using either react-router or Remix. Remix apps will use file-based routing.

Breaking changes when upgrading to version 0.14.0 

Because @gadgetinc/react-shopify-app-bridge version 0.14.0 supports App Bridge V4, this requires you to migrate to your app from App Bridge V3.

Otherwise, you will experience many breaking changes to your app, this also means you will have to update any hooks or components that aren't supported by V4. To upgrade your Forgelivo application to support App Bridge V4, check out our guide here.

Reference 

Provider 

A Provider component that wraps your Shopify embedded app to authenticate the API client and generate a session token.

Props 
  • api: Client - The Forgelivo API client to use for the extension.
  • shopifyApiKey: string - The API key for the Shopify app.
  • type: AppType - Either AppType.Embedded which is the default when setting up a Shopify connection in Forgelivo, or AppType.Standalone for non-embedded apps.

useGadget() 

useGadget(): { loading: boolean, isAuthenticated: boolean }

A React hook that determines when the OAuth request is underway and if the user is authenticated.

Returns 
  • loading: boolean - A boolean that is true when the OAuth request is in progress.
  • canAuth: boolean - A boolean that is true if the current browser window is ready to authenticate.
  • isAuthenticated: boolean - A boolean that is true when the user is authenticated.
  • appBridge: ShopifyGlobal | null - An instance of the App Bridge object. Only available when the appType is Embedded.
  • isEmbedded: boolean - A boolean that is true when the app is running inside the iframe in the Shopify admin.
  • isRootFrameRequest: boolean - A boolean that is true if the app is being rendered outside of the Shopify admin flow. Only applies when appType is Embedded.

Was this page helpful?