Saltar al contenido principal

Tutorial de Shopify App Bridge 4: cree aplicaciones integradas en 2026

Cree aplicaciones de administración integradas de Shopify con App Bridge 4: tokens de sesión, intercambio de tokens, navegación, modales, selectores de recursos y configuración de Polaris React 13.

E
ECOSIRE Research and Development Team
|4 de mayo de 20267 min de lectura1.3k Palabras|

Este artículo actualmente está disponible solo en inglés. La traducción estará disponible próximamente.

App Bridge is the JavaScript library that connects an embedded Shopify app (running inside an iframe in the merchant admin) to the Shopify admin chrome — navigation, modals, toasts, resource pickers, contextual save bars.

App Bridge is the JavaScript library that connects an embedded Shopify app (running inside an iframe in the merchant admin) to the Shopify admin chrome — navigation, modals, toasts, resource pickers, contextual save bars. Version 4 (released 2024, default in 2026) is a complete rewrite: framework-agnostic, no React Provider, session tokens by default, no more CommonJS shim. If you started with App Bridge 2 or 3, the upgrade requires real changes. This tutorial walks through a fresh embedded app build using App Bridge 4 with React 19.

Key Takeaways

  • App Bridge 4 ships as a single ES module loaded from Shopify's CDN — no npm install for the runtime
  • Session tokens replace the old OAuth-redirect dance; backend exchanges them for offline access tokens
  • APIs are now shopify.<feature> globals (e.g., shopify.toast.show, shopify.modal.show)
  • The <App Provider> wrapper from App Bridge React is gone — APIs work without React context
  • Resource Picker, Contextual Save Bar, and Loading Bar are now web components (<ui-resource-picker> etc.)
  • Polaris React 13+ is the recommended UI kit and ships compatible with App Bridge 4

What "embedded" means

An embedded Shopify app is a page in the merchant admin (https://admin.shopify.com/store/{shop}/apps/{app}) that loads your URL inside an iframe. The merchant never leaves Shopify; you get a sandboxed UI surface and a session token in every request. This is the mode App Store apps and most agency-built apps use today.

Non-embedded apps run on your own domain with full-page redirects. Shopify still supports them but they break the unified admin UX and are not eligible for App Store featured placement.

Project setup

Start from the official template:

npm create @shopify/app@latest -- --template node

You get a Remix backend, Polaris frontend, Prisma session storage, and App Bridge wired up. For our purposes we'll show the App Bridge moving parts in a Next.js app router build, since most of our customers are on Next.

<!-- app/layout.tsx — load App Bridge from CDN in <head> -->
<script
  src="https://cdn.shopify.com/shopifycloud/app-bridge.js"
  data-api-key={process.env.NEXT_PUBLIC_SHOPIFY_API_KEY}
></script>

That's the entire runtime. App Bridge attaches itself to window.shopify once the script loads. You access it as window.shopify or shopify (if the global is declared in TypeScript).

Session tokens for authenticated requests

The session token is a JWT signed with your client secret, valid for 60 seconds, that App Bridge mints on demand. You attach it to every request to your backend.

// Frontend
async function api(path: string, init?: RequestInit) {
  const token = await shopify.idToken();
  return fetch(`/api${path}`, {
    ...init,
    headers: { ...init?.headers, Authorization: `Bearer ${token}` },
  });
}
// Backend (Next.js route handler)
import { jwtVerify } from 'jose';
const secret = new TextEncoder().encode(process.env.SHOPIFY_API_SECRET!);

async function getShop(req: Request): Promise<string> {
  const auth = req.headers.get('authorization')?.replace('Bearer ', '');
  if (!auth) throw new Response('Unauthorized', { status: 401 });
  const { payload } = await jwtVerify(auth, secret);
  return new URL(payload.dest as string).hostname; // shop.myshopify.com
}

The token's dest claim tells you which shop made the request. Trust nothing else from the client.

Token exchange: getting an offline access token

The session token is enough to identify the shop, but not enough to call the Admin API. You exchange it for a long-lived offline access token via Shopify's token-exchange endpoint:

async function exchangeToken(shop: string, sessionToken: string) {
  const res = await fetch(`https://${shop}/admin/oauth/access_token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.SHOPIFY_API_KEY,
      client_secret: process.env.SHOPIFY_API_SECRET,
      grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
      subject_token: sessionToken,
      subject_token_type: 'urn:ietf:params:oauth:token-type:id_token',
      requested_token_type: 'urn:shopify:params:oauth:token-type:offline-access-token',
    }),
  });
  const { access_token } = await res.json();
  return access_token;
}

Cache the offline token in your database keyed by shop. It only expires when the merchant uninstalls the app.

Common UI APIs

Toasts

shopify.toast.show('Product saved', { duration: 3000 });
shopify.toast.show('Failed to save', { isError: true });

Modals

<ui-modal id="confirm-modal">
  <s-paragraph>Are you sure you want to archive 142 products?</s-paragraph>
  <ui-title-bar title="Confirm archive">
    <button variant="primary" tone="critical" onClick="archive()">Archive</button>
    <button onClick="document.getElementById('confirm-modal').hide()">Cancel</button>
  </ui-title-bar>
</ui-modal>
document.getElementById('confirm-modal').show();

Resource Picker

const result = await shopify.resourcePicker({ type: 'product', multiple: true });
if (result) {
  console.log(result.selection); // [{ id, title, handle, ... }]
}

Contextual Save Bar

The save bar pins to the bottom of the admin and is the canonical "you have unsaved changes" pattern.

<ui-save-bar id="save-bar">
  <button variant="primary" onClick="save()">Save</button>
  <button onClick="discard()">Discard</button>
</ui-save-bar>

Show it via document.getElementById('save-bar').show() when state diverges from saved.

App Bridge owns the URL bar. Use its navigation API instead of router.push to keep the admin chrome in sync:

shopify.navigation.navigate('/products/123');

For external Shopify admin links (orders, customers):

shopify.navigation.navigate('shopify://admin/products/123');

Polaris UI

Polaris is Shopify's React component library matching the admin's visual language. Install Polaris React 13+:

npm install @shopify/polaris
import { AppProvider, Page, Card, Button } from '@shopify/polaris';
import enTranslations from '@shopify/polaris/locales/en.json';

export default function ProductsPage() {
  return (
    <AppProvider i18n={enTranslations}>
      <Page title="Products" primaryAction={{ content: 'Add product' }}>
        <Card>
          <Button onClick={() => shopify.toast.show('Hello')}>Toast me</Button>
        </Card>
      </Page>
    </AppProvider>
  );
}

Webhooks for app lifecycle

Subscribe to these at install time. They are mandatory for App Store approval:

TopicPurpose
app/uninstalledClean up shop's data, revoke access token
customers/data_requestGDPR — surface customer data
customers/redactGDPR — delete customer data
shop/redactGDPR — delete shop data after 48h

Verify HMAC on every webhook. We covered the full pattern in Shopify webhooks: HMAC, retries, idempotency.

App Bridge 3 vs 4 migration

Featurev3v4
Install@shopify/app-bridge npmCDN script
React API<Provider config={...}>Globals via shopify.*
Session tokengetSessionToken(app)shopify.idToken()
ToastToast.create(app, opts)shopify.toast.show()
Resource PickerResourcePicker.create()shopify.resourcePicker()
ModalModal.create()<ui-modal> web component
LoadingLoading.create()shopify.loading(true)

The migration is mostly mechanical but expect 4-8 hours for a non-trivial app.

Performance considerations

  • App Bridge 4 adds ~12 KB gzipped to your initial load.
  • The iframe boots in ~120 ms once the merchant clicks your app tile.
  • Avoid synchronous calls to shopify.idToken() in tight loops — token minting is rate-limited at ~1/sec per session.
  • Use shopify.config.shop to detect the shop synchronously without a backend round trip.

Frequently Asked Questions

Do I need React to use App Bridge 4?

No. App Bridge 4 is framework-agnostic. The web components and shopify.* globals work in vanilla JS, Vue, Svelte, or React. Polaris React is React-only, but App Bridge isn't.

How do I test embedded apps locally?

Use shopify app dev from the CLI. It tunnels your local server through Cloudflare and registers the redirect URLs with Shopify. The CLI also handles partner-account auth so the embedded iframe can load against your dev shop.

Can I open my embedded app in a new tab?

The merchant can — Shopify exposes "Open in new tab" on every embedded app. When opened that way, App Bridge runs in standalone mode (no parent admin chrome). Your code should handle both cases. Use shopify.environment.embedded to check.

What about Shopify CLI vs raw build?

CLI accelerates scaffolding (Prisma, session storage, OAuth) but you can absolutely roll your own. We use raw Next.js + Drizzle for most agency builds because we need control over auth and data persistence. The CLI template is excellent for App Store apps where standard patterns are preferred.

How does this work with the new GraphQL Admin API?

App Bridge handles auth; once you have the offline access token, you call the Shopify Admin GraphQL API the same way as any other GraphQL client. The two systems are loosely coupled.


ECOSIRE builds embedded Shopify apps for Plus and standard merchants — billing, custom workflows, ERP connectors. Our Shopify app development team handles App Bridge migrations, App Store submissions, and ongoing maintenance.

E

Escrito por

ECOSIRE Team

Technical Writing

The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.

ECOSIRE

Escala tu tienda Shopify

Servicios personalizados de desarrollo, optimización y migración para comercio electrónico de alto crecimiento.