BigCommerce App Extensions 

BigCommerce App Extensions allow developers to extend the control panel's capabilities by registering custom menu items that appear on select native control panel pages.

When a control panel user clicks an App Extension-generated menu item, the app can either render content in a side panel without navigating the user away from the native page, or it can redirect the user to the app's home iframe in the Apps sub-menu, and render App Extension-specific content there.

Your Gadget frontend routes can be used to power App Extensions.

Adding a new App Extension 

To add a new App Extension to a Gadget app:

Step 1: Set up a BigCommerce connection 

Set up a BigCommerce connection in Gadget and install on a BigCommerce sandbox store. Make sure that the App Extensions : manage OAuth scope is selected when setting up the connection. You don't need to worry about subscribing to webhooks at this time.

Step 2: Add a field to track the App Extension ID 

Add an appExtensionId string field to your bigcommerce/store model.

Each app can install up to 2 App Extensions per store. If you are installing 2 App Extensions, you can use 2 fields or store both IDs in a single string or json field.

Step 3: Register the App Extension with the store on install 

Paste the following code into api/models/bigcommerce/store/install.js to create a new App Extension and save the App Extension ID to your bigcommerce/store model when your app is installed on a store.

Make sure to update the input variable of the GraphQL mutation to match the type of App Extension you want to create:

api/models/bigcommerce/store/install.js
JavaScript
1import { applyParams, save, ActionOptions } from "gadget-server";
2
3export const run: ActionRun = async ({ params, record }) => {
4 applyParams(params, record);
5 await save(record);
6};
7
8export const onSuccess: ActionOnSuccess = async ({ record, logger, api }) => {
9 const accessToken = (
10 await api.internal.bigcommerce.store.findFirst({
11 filter: { storeHash: { equals: record.storeHash } },
12 })
13 ).accessToken;
14
15 // use fetch for GraphQL request (GraphQL not supported by built-in client)
16 const response = await fetch(
17 `https://api.bigcommerce.com/stores/${record.storeHash}/graphql`,
18 {
19 method: "POST",
20 headers: {
21 "Content-Type": "application/json",
22 Accept: "application/json",
23 "X-Auth-Token": accessToken,
24 },
25 body: JSON.stringify({
26 query: `mutation AppExtension($input: CreateAppExtensionInput!) {
27 appExtension {
28 createAppExtension(input: $input) {
29 appExtension {
30 id
31 context
32 model
33 url
34 label {
35 defaultValue
36 locales {
37 value
38 localeCode
39 }
40 }
41 }
42 }
43 }
44 }`,
45 variables: {
46 // edit input to match your desired App Extension
47 input: {
48 context: "PANEL",
49 model: "PRODUCTS",
50 url: "/products/${id}/interactions",
51 label: {
52 defaultValue: "Interactions",
53 locales: [
54 {
55 value: "Interaction Notes",
56 localeCode: "en-US",
57 },
58 {
59 value: "Notas de interacción",
60 localeCode: "es-MX",
61 },
62 ],
63 },
64 },
65 },
66 }),
67 }
68 );
69
70 const jsonResponse = await response.json();
71
72 if (jsonResponse.errors) {
73 logger.error({ errors: jsonResponse.errors }, "Error creating app extension");
74 }
75
76 // save the App Extension id to your bigcommerce/store model
77 await api.internal.bigcommerce.store.update(record.id, {
78 appExtensionId:
79 jsonResponse.data.appExtension.createAppExtension.appExtension.id,
80 });
81};
82
83export const options: ActionOptions = {
84 actionType: "create",
85};
1import { applyParams, save, ActionOptions } from "gadget-server";
2
3export const run: ActionRun = async ({ params, record }) => {
4 applyParams(params, record);
5 await save(record);
6};
7
8export const onSuccess: ActionOnSuccess = async ({ record, logger, api }) => {
9 const accessToken = (
10 await api.internal.bigcommerce.store.findFirst({
11 filter: { storeHash: { equals: record.storeHash } },
12 })
13 ).accessToken;
14
15 // use fetch for GraphQL request (GraphQL not supported by built-in client)
16 const response = await fetch(
17 `https://api.bigcommerce.com/stores/${record.storeHash}/graphql`,
18 {
19 method: "POST",
20 headers: {
21 "Content-Type": "application/json",
22 Accept: "application/json",
23 "X-Auth-Token": accessToken,
24 },
25 body: JSON.stringify({
26 query: `mutation AppExtension($input: CreateAppExtensionInput!) {
27 appExtension {
28 createAppExtension(input: $input) {
29 appExtension {
30 id
31 context
32 model
33 url
34 label {
35 defaultValue
36 locales {
37 value
38 localeCode
39 }
40 }
41 }
42 }
43 }
44 }`,
45 variables: {
46 // edit input to match your desired App Extension
47 input: {
48 context: "PANEL",
49 model: "PRODUCTS",
50 url: "/products/${id}/interactions",
51 label: {
52 defaultValue: "Interactions",
53 locales: [
54 {
55 value: "Interaction Notes",
56 localeCode: "en-US",
57 },
58 {
59 value: "Notas de interacción",
60 localeCode: "es-MX",
61 },
62 ],
63 },
64 },
65 },
66 }),
67 }
68 );
69
70 const jsonResponse = await response.json();
71
72 if (jsonResponse.errors) {
73 logger.error({ errors: jsonResponse.errors }, "Error creating app extension");
74 }
75
76 // save the App Extension id to your bigcommerce/store model
77 await api.internal.bigcommerce.store.update(record.id, {
78 appExtensionId:
79 jsonResponse.data.appExtension.createAppExtension.appExtension.id,
80 });
81};
82
83export const options: ActionOptions = {
84 actionType: "create",
85};

For production apps, you may also want to run the same code in api/models/bigcommerce/store/reinstall.js.

Step 4: Set up frontend routing 

Add a new file to your web/routes folder and add a route to your router in web/components/App.jsx.

For example, if you used the above example for your App Extension and set the url to /products/${id}/interactions, you would need to add the following to your route definition in web/components/App.jsx

web/components/App.jsx
React
1import AppExtension from "../routes/appExtension";
2
3// ... other imports
4
5function App() {
6 // add route to router definition
7 const router = createBrowserRouter(
8 createRoutesFromElements(
9 <Route path="/" element={<Layout />}>
10 {/** ... existing routes */}
11 <Route path="/products/:productId/interactions" element={<AppExtension />} />
12 </Route>
13 )
14 );
15
16 return <RouterProvider router={router} />;
17}
18
19// ... more code
1import AppExtension from "../routes/appExtension";
2
3// ... other imports
4
5function App() {
6 // add route to router definition
7 const router = createBrowserRouter(
8 createRoutesFromElements(
9 <Route path="/" element={<Layout />}>
10 {/** ... existing routes */}
11 <Route path="/products/:productId/interactions" element={<AppExtension />} />
12 </Route>
13 )
14 );
15
16 return <RouterProvider router={router} />;
17}
18
19// ... more code

Then create a new file at web/routes/appExtension.jsx and build your App Extension UI:

web/routes/appExtension.jsx
React
1import { Panel, Text } from "@bigcommerce/big-design";
2import { useParams } from "react-router";
3
4export default function () {
5 // useParams hook to get route param from BigCommerce
6 const { productId } = useParams();
7
8 return (
9 <>
10 <Panel description="Successfully created an App Extension!">
11 <Text>This extension is for product {productId}!</Text>
12 </Panel>
13 </>
14 );
15}
1import { Panel, Text } from "@bigcommerce/big-design";
2import { useParams } from "react-router";
3
4export default function () {
5 // useParams hook to get route param from BigCommerce
6 const { productId } = useParams();
7
8 return (
9 <>
10 <Panel description="Successfully created an App Extension!">
11 <Text>This extension is for product {productId}!</Text>
12 </Panel>
13 </>
14 );
15}

The useParams hook is used to grab the productId included in the route path.

Step 5: Test your App Extension 

Once you finish adding your routes and the custom backend code, you need to:

  • Uninstall your app from the sandbox.
  • Delete the existing bigcommerce/store record from the Gadget database. This can be done on the bigcommerce/store model's data page: api/models/bigcommerce/store/data.
  • Install your app back on the sandbox.

This will run your GraphQL mutation on install and register the App Extension.

Now you can navigate to your App Extension and start building.

For more information on building frontends, read the single-click app frontend docs.

Was this page helpful?