Create a Shopify App for Product Vendors & Admin options using ReactJS & Polaris
- Abhilash Sivaraman

- Apr 18, 2025
- 3 min read
🧱 Requirements
Shopify Partner Account
Development store
Shopify CLI
Frontend: React.js with App Bridge + Polaris
App Hosted externally (e.g., Vercel/Netlify)
Authenticated using Shopify App Bridge + JWT token
✅ Step-by-Step Guide: Shopify Embedded App in React Only
🧩 Step 1: Create React App
npx create-react-app vendor-app
cd vendor-app📦 Step 2: Install Dependencies
npm install @shopify/app-bridge-react @shopify/polaris @shopify/app-bridge @shopify/app-bridge-utilsAlso install @shopify/polaris CSS:
npm install @shopify/polaris-tokens⚙️ Step 3: Setup App Bridge Provider
In src/index.js:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import {
AppBridgeProvider
} from "@shopify/app-bridge-react";
import {
Provider as PolarisProvider
} from "@shopify/polaris";
import "@shopify/polaris/build/esm/styles.css";
const config = {
apiKey: process.env.REACT_APP_SHOPIFY_API_KEY, // from Shopify Partner dashboard
host: new URLSearchParams(window.location.search).get("host"),
forceRedirect: true,
};
ReactDOM.render(
<PolarisProvider>
<AppBridgeProvider config={config}>
<App />
</AppBridgeProvider>
</PolarisProvider>,
document.getElementById("root")
);🗂️ Step 4: Add Navigation (Admin Menu)
In src/App.js:
import {
NavigationMenu
} from "@shopify/app-bridge-react";
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
import Vendors from "./pages/Vendors";
import VendorDetail from "./pages/VendorDetail";
function App() {
return (
<>
<NavigationMenu
navigationLinks={[
{
label: "Vendors",
destination: "/vendors",
},
]}
/>
<Router>
<Routes>
<Route path="/vendors" element={<Vendors />} />
<Route path="/vendors/:name" element={<VendorDetail />} />
</Routes>
</Router>
</>
);
}
export default App;🗂️ Step 5:
/vendors
Page
src/pages/Vendors.js
import { Page, Card, ResourceList, Text } from "@shopify/polaris";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
const Vendors = () => {
const [vendors, setVendors] = useState([]);
useEffect(() => {
const fetchProducts = async () => {
const token = window.sessionToken; // get from App Bridge utils
const res = await fetch("/admin/api/2024-01/products.json", {
headers: {
"X-Shopify-Access-Token": token,
},
});
const data = await res.json();
const vendorMap = {};
data.products.forEach((p) => {
const vendor = p?.vendor || p?.metafields?.find(mf => mf.key === "vendor_name")?.value;
if (vendor) vendorMap[vendor] = true;
});
setVendors(Object.keys(vendorMap).map((v) => ({ name: v })));
};
fetchProducts();
}, []);
return (
<Page title="Vendors">
<Card>
<ResourceList
items={vendors}
renderItem={(vendor) => (
<ResourceList.Item
id={vendor.name}
accessibilityLabel={`View ${vendor.name}`}
>
<Link to={`/vendors/${vendor.name}`}>{vendor.name}</Link>
</ResourceList.Item>
)}
/>
</Card>
</Page>
);
};
export default Vendors;📄 Step 6:
/vendors/:name
Page
src/pages/VendorDetail.js
import { useParams } from "react-router-dom";
import { Page, Card, ResourceList, Text } from "@shopify/polaris";
import { useEffect, useState } from "react";
const VendorDetail = () => {
const { name } = useParams();
const [products, setProducts] = useState([]);
const [orders, setOrders] = useState([]);
useEffect(() => {
const token = window.sessionToken;
const fetchProducts = async () => {
const res = await fetch("/admin/api/2024-01/products.json", {
headers: {
"X-Shopify-Access-Token": token,
},
});
const data = await res.json();
const filtered = data.products.filter(p => p.vendor === name);
setProducts(filtered);
};
const fetchOrders = async () => {
const res = await fetch("/admin/api/2024-01/orders.json", {
headers: {
"X-Shopify-Access-Token": token,
},
});
const data = await res.json();
const vendorOrders = data.orders.filter(order =>
order.line_items.some(li => li.vendor === name)
);
setOrders(vendorOrders);
};
fetchProducts();
fetchOrders();
}, [name]);
return (
<Page title={`Vendor: ${name}`}>
<Card title="Products">
<ResourceList
items={products}
renderItem={(p) => (
<ResourceList.Item id={p.id}>
<Text>{p.title}</Text>
</ResourceList.Item>
)}
/>
</Card>
<Card title="Orders">
<ResourceList
items={orders}
renderItem={(o) => (
<ResourceList.Item id={o.id}>
<Text>Order #{o.name}</Text>
</ResourceList.Item>
)}
/>
</Card>
</Page>
);
};
export default VendorDetail;🔐 Step 7: Handle Access Token (JWT)
You need to use App Bridge Utils to get the JWT session token to call Admin API:
import { getSessionToken } from "@shopify/app-bridge-utils";
getSessionToken(app).then(token => {
window.sessionToken = token;
});Call this on app load (App.js) inside useEffect.
🚀 Final Hosting (Vercel/Netlify)
Push your React app to GitHub.
Deploy using Vercel or Netlify.
Use the deployed URL to register the app in Shopify Partner → App Setup > App URL.
Add /auth/callback, /auth, / to whitelist.
🧩 Notes
You must register your app from Partner dashboard.
Use Admin API scopes like:
read_products
read_orders
read_customers (optional)
All calls must pass JWT session token obtained via App Bridge.






























































































Comments