---
title: Network Features
description: Admin UI extensions make it possible to surface contextual app functionality within the Shopify Admin interface.
api_version: 2025-10
api_name: admin-extensions
source_url:
html: https://shopify.dev/docs/api/admin-extensions/latest/network-features
md: https://shopify.dev/docs/api/admin-extensions/latest/network-features.md
---
# Network Features
Admin UI extensions make it possible to surface contextual app functionality within the Shopify Admin interface.
## Overview
Extend the Shopify Admin with UI Extensions.
[](https://shopify.dev/docs/api/admin-extensions/latest/#app-authentication)
[App authenticationMake authenticated requests to your app's backend](https://shopify.dev/docs/api/admin-extensions/latest/#app-authentication)
[](https://shopify.dev/docs/api/admin-extensions/latest/#direct-api-access)
[Direct API accessAccess the Shopify GraphQL API directly](https://shopify.dev/docs/api/admin-extensions/latest/#direct-api-access)
[](https://shopify.dev/docs/api/admin-extensions/latest/#custom-protocols)
[Custom protocolsEasily construct URLs to navigate to common locations](https://shopify.dev/docs/api/admin-extensions/latest/#custom-protocols)

## App Authentication
Admin UI extensions can also make authenticated calls to your app's backend. When you use `fetch()` to make a request to your app's configured auth domain or any of its subdomains, an `Authorization` header is automatically added with a Shopify [OpenID Connect ID Token](https://shopify.dev/docs/api/app-home/apis/id-token). There's no need to manually manage ID tokens.
Relative URLs passed to `fetch()` are resolved against your app's `app_url`. This means if your app's backend is on the same domain as your `app_url`, you can make requests to it using `fetch('/path')`.
If you need to make requests to a different domain, you can use the [`auth.idToken()` method](https://shopify.dev/docs/api/admin-extensions/api/standard-api#standardapi-propertydetail-auth) to retrieve the ID token and manually add it to your request headers.
### Examples
* #### Make requests to your app's backend
##### Get Product Data
```tsx
import {render} from 'preact';
import {useEffect, useState} from 'preact/hooks';
export default async () => {
render(, document.body);
}
// Get product info from app backend
async function getProductInfo(id) {
const res = await fetch(`/api/products/${id}`);
return res.json();
}
function Extension() {
// Contextual "input" data passed to this extension:
const {data} = shopify;
const productId = data.selected?.[0]?.id;
const [productInfo, setProductInfo] = useState();
useEffect(() => {
getProductInfo(productId).then(setProductInfo);
}, [productId]);
return (
Info: {productInfo?.title}
);
}
```
##### Get Data from a different domain
```tsx
import {render} from 'preact';
import {useEffect, useState} from 'preact/hooks';
export default async () => {
render(, document.body);
}
// Get product info from a different app backend
async function getProductInfo(id, auth) {
const token = await auth.idToken();
const res = await fetch(`https://app.example.com/api/products/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return res.json();
}
function Extension() {
// Contextual "input" data passed to this extension:
const {data, auth} = shopify;
const productId = data.selected?.[0]?.id;
const [productInfo, setProductInfo] = useState();
useEffect(() => {
getProductInfo(productId, auth).then(setProductInfo);
}, [productId, auth]);
return (
Info: {productInfo?.title}
);
}
```
## Direct API access
You can make Shopify Admin API requests directly from your extension using the [query API](https://shopify.dev/docs/api/admin-extensions/api/standard-api#standardapi-propertydetail-query) or the standard [web fetch API](https://developer.mozilla.org/en-US/docs/Web/API/fetch)!
Any `fetch()` calls from your extension to Shopify's Admin GraphQL API are automatically authenticated by default. These calls are fast too, because Shopify handles requests directly.
Direct API requests use [online access](https://shopify.dev/docs/apps/build/authentication-authorization/access-token-types/online-access-tokens) mode by default. If you want to use [offline access](https://shopify.dev/docs/apps/build/authentication-authorization/access-token-types/offline-access-tokens) mode, you can set the `direct_api_mode` property to `offline` in your [app TOML file](https://shopify.dev/docs/apps/tools/cli/configuration#admin).
Note: Direct API can't be used to manage storefront access tokens.
[](https://shopify.dev/docs/api/admin-extensions#direct-api-access)
[NoteDirect API can't be used to manage storefront access tokens.](https://shopify.dev/docs/api/admin-extensions#direct-api-access)
[](https://shopify.dev/docs/api/usage/access-scopes)
[Developer guideLearn more about access scopes](https://shopify.dev/docs/api/usage/access-scopes)
### Examples
* #### Query Shopify data
##### Fetch Product data
```tsx
import {render} from 'preact';
export default async () => {
const productId = shopify.data.selected?.[0]?.id;
const product = await getProduct(productId);
render(, document.body);
};
async function getProduct(id) {
const res = await fetch('shopify:admin/api/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query GetProduct($id: ID!) {
product(id: $id) {
title
}
}
`,
variables: {id},
}),
});
const {data} = await res.json();
return data.product;
}
function Extension({product}) {
return (
The selected product title is {product.title}
);
}
```
##### Query Product data
```tsx
import {render} from 'preact';
export default async () => {
const productId = shopify.data.selected?.[0]?.id;
const {
data: {product},
} = await shopify.query(
`
query GetProduct($id: ID!) {
product(id: $id) {
title
}
}
`,
{variables: {id: productId}},
);
render(, document.body);
};
function Extension({product}) {
return (
The selected product title is {product.title}
);
}
```
## Custom Protocols
Custom protocols make it easier to navigate to common locations, and construct URLs.
Shopify Protocol
Use the `shopify:admin` protocol when you want to construct a URL with a root of the Shopify Admin.
App Protocol
Use the `app:` protocol to construct a URL for your app. Shopify will handle constructing the base URL for your app. This works for both embedded and non-embedded apps.
Extension Protocol
Triggers an action extension from a block extension using the `extension:` protocol. The `extensionTarget` is the target of the action extension. The handle is the handle of the action extension that will be opened.
Relative Urls
Relative urls are relative to your app and are useful when you want to link to a route within your app. This works for both embedded and non-embedded apps.
### Examples
* #### shopify:admin
##### Link to Product Page
```tsx
Link to Product Page;
```
##### Fetch data
```ts
fetch('shopify:admin/api/graphql.json', {
method: 'POST',
body: JSON.stringify(simpleProductQuery),
});
```
## Security
UI Extensions run on a different origin than the Shopify Admin. For network calls to succeed, your server must support [cross-origin resource sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) for the origin `https://extensions.shopifycdn.com`.
If you have a custom [`Access-Control-Allow-Origin` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) set, you must include `https://extensions.shopifycdn.com` in the list of allowed origins.
If you are using the [Shopify App Remix Template](https://github.com/Shopify/shopify-app-template-remix), this is done automatically for you.