Hello! It's great to see you again.
In our last lesson, we mastered Shopify Polaris, learning how to build a user interface that looks and feels like a native part of the Shopify Admin. We now have the skills to create the "face" of our app. But a pretty face isn't enough; an app needs to be functional.
Today, we'll bring that UI to life by connecting it to the heart of the Shopify platform: the merchant's store data. This lesson synthesizes everything we've covered on App Bridge and Polaris, focusing on the complete, end-to-end flow of data from Shopify's servers to your app's front end.
Given your background in full-stack development, you'll find the pattern familiar: a backend process fetches data, and a frontend component renders it. We'll simply be using Shopify's specialized tools for each step.
By the end of this lesson, you will be able to create an embedded app page that can display and interact with store data.
The Anatomy of an Embedded App Page
Let's quickly revisit the architecture of an embedded app. As a developer, you are responsible for rendering the "App surface," but this surface must communicate with the Shopify Admin (via App Bridge) and present a consistent UI (via Polaris).

Today's goal is to make that "App surface" dynamic by populating it with data from the merchant's store, like a list of their products.
The Data Flow: From Shopify to Your Component
In a modern Shopify app built with the Remix template, fetching and displaying data follows a clear, secure pattern that separates server-side and client-side concerns.
-
The Route Component (e.g.,
app/routes/app.products.jsx): This file defines a new page in your app. It exports two key things:- A
loaderfunction that runs only on the server. - A React component that runs on the client (the browser).
- A
-
The
loaderFunction (Backend): This is where you perform secure operations. The Shopify CLI provides anauthenticate.admin(request)helper. This gives you anadminobject, which contains a pre-configured GraphQL client. You use this client to query the Shopify Admin API for the data you need (e.g., products, orders). Theloaderthen returns this data as a JSON response. -
The
useLoaderDataHook (Connecting Backend to Frontend): In your React component, you call theuseLoaderDatahook. This hook provides the data that was returned from yourloaderfunction. -
The Polaris Component (Frontend): You take the data from
useLoaderDataand pass it as props to Polaris components likeResourceListorCardto render the UI for the merchant.
This architecture ensures that your API keys and secret tokens are never exposed to the browser, as all API calls happen securely on the server within the loader.
Part 1: Fetching and Displaying Products
Let's walk through building a new page in our app that fetches a list of products from the store and displays them. The following video provides an excellent step-by-step guide using the latest Shopify app template. We'll break it down into logical steps.
Getting Started with Shopify App Bridge - Create a Shopify App
The video 'Getting Started with Shopify App Bridge' from the WeeklyHow channel demonstrates the entire process of creating a new page, fetching data, and displaying it. We will focus on the sections that build out a 'Products' page.
This is a practical walkthrough. Follow these segments in order: Creating the Page & UI Shell (08:53 - 10:51): First, watch how to create a new route file (app.products.tsx) and use Polaris Page, Layout, and Card components to build the basic UI structure. Fetching Data in the Loader (17:20 - 23:00): This is the core backend part. Pay close attention to how the loader function is defined, how admin.graphql is used to make an API call, and how the data is returned using the json helper from Remix. Updating API Scopes (23:00 - 27:47): This is a critical, real-world step. The video shows the error you get when your app doesn't have permission to read products and how to fix it by updating the shopify.app.toml file and redeploying the app's configuration. You will encounter this constantly as a freelancer. Rendering the Data (27:47 - 33:42): Finally, see how the fetched data is retrieved in the component using useLoaderData and rendered using the Polaris ResourceList component. Note the use of Thumbnail to display product images.
After watching, let's crystallize the key steps:
- Create a new file in
/app/routes/(e.g.,app.products.tsx) to define the new page. - Define a
loaderfunction that isasyncand usesawait authenticate.admin(request). - Construct a GraphQL query as a string and pass it to
admin.graphql(). Remember to request the specific fields you need (e.g.,id,title,featuredImage). - Update your app's scopes in
shopify.app.tomlto include necessary permissions likeread_products. - Return the data from the
loaderusingjson({ products: productsData.products.edges }). - In your React component, get the data using
const { products } = useLoaderData(). - Map over the data and render it using an appropriate Polaris component like
ResourceList.
Test your understanding!
In the data fetching pattern we just saw, why is it crucial to perform the GraphQL query inside the loader function instead of directly in the React component using a useEffect hook and fetch?
Show answer
There are two main reasons:
- Security: The
loaderfunction runs on your server. This allows it to safely use the app's API credentials to make authenticated requests to Shopify. If you were to make the API call from the frontend (useEffect), you would have to expose your secret API keys to the browser, which is a major security vulnerability. - Performance & Simplicity: The Remix framework is designed for this server-side data loading pattern. It handles the data transfer from server to client automatically. This simplifies your component logic (no need for loading/error states managed by
useEffect) and supports server-side rendering (SSR), which can lead to faster page loads.
Part 2: Interacting with Store Data via ResourcePicker
Displaying data is only half the story. A truly useful app allows merchants to interact with their data. One of the most common and powerful ways to do this is with App Bridge's ResourcePicker. It opens a modal that allows the merchant to browse, search, and select their Products, Variants, or Collections.
The official Shopify documentation provides a fantastic tutorial on building a QR code generator app. We will focus on the part where it implements the product selector.
Build a Shopify app using React Router
The Shopify developer documentation for 'Build a Shopify app using React Router' contains a complete walkthrough. We'll zero in on the sections that create and use the product selector.
Read through the section titled 'Create a QR code form'. You don't need to implement the entire form, but focus on understanding these key concepts: Set up the form route: Notice the creation of app.qrcodes.$id.jsx, which shows how to handle both creating new items and editing existing ones. Add a product selector: This is the most important part. See how the App Bridge ResourcePicker is invoked to open the product selection modal. Pay attention to how the selection is handled and used to update the component's state. Lay out the form: Skim this section to see how various Polaris web components (s-page, s-text-field, s-button) are used to build the form's UI. This reinforces what you learned in the previous lesson.
The core interaction logic for the ResourcePicker looks like this (adapted from the tutorial for clarity):
import { useAppBridge } from "@shopify/app-bridge-react";
import { useState } from "react";
function ProductSelector() {
const shopify = useAppBridge();
const [selectedProduct, setSelectedProduct] = useState(null);
async function selectProduct() {
const products = await shopify.resourcePicker({
type: "product",
action: "select",
multiple: false, // Set to true to allow multiple selections
});
if (products) {
const { id, title, images } = products[0];
// You now have the product data. You can save it to your component's state.
setSelectedProduct({ id, title, image: images[0]?.originalSrc });
// In a real app, you would likely send this ID to your backend
// to save it in your database.
}
}
// ... JSX to display the selected product and a button to trigger selectProduct
}
This pattern is incredibly powerful. You get a native, feature-rich product selection UI with just a few lines of code, and you receive clean, structured data back to use in your application.
Conclusion
In this lesson, we bridged the gap between our frontend UI and Shopify's backend data. You've built a complete, full-stack slice of functionality within an embedded app, a core competency for any Shopify developer.
Key Takeaways:
- Embedded app pages are created as new routes within your app's file structure.
- The Remix
loaderfunction is the secure, server-side gateway for fetching data from the Shopify Admin API using theadmin.graphqlclient. - Data from the
loaderis passed to your frontend component via theuseLoaderDatahook. - Polaris components like
ResourceListandCardprovide a consistent and professional way to display store data to the merchant. - App Bridge's
ResourcePickeris an essential tool for enabling merchants to interact with and select resources like products and collections from within your app.
In our next lesson, we will build on the interaction patterns we saw today. We will explore how to use App Bridge actions to trigger native Shopify UI elements like modals and toast messages. This will allow us to provide clear feedback to the merchant after they perform an action, such as confirming that a product has been saved or alerting them to an error.