--- title: App proxy description: >- [App proxies](/docs/apps/online-store/app-proxies) take requests to Shopify links, and redirect them to external links. The `authenticate.public.appProxy` function validates requests made to app proxies, and returns a context to enable querying Shopify APIs. > Note: If the store has not installed the app, store-related properties such as `admin` or `storefront` will be `undefined` api_version: v1 latest api_name: shopify-app-react-router source_url: html: >- https://shopify.dev/docs/api/shopify-app-react-router/latest/authenticate/public/app-proxy md: >- https://shopify.dev/docs/api/shopify-app-react-router/latest/authenticate/public/app-proxy.md --- # App proxy [App proxies](https://shopify.dev/docs/apps/online-store/app-proxies) take requests to Shopify links, and redirect them to external links. The `authenticate.public.appProxy` function validates requests made to app proxies, and returns a context to enable querying Shopify APIs. **Note:** If the store has not installed the app, store-related properties such as \admin\ or \storefront\ will be \undefined\ ## authenticate.​public.​app​Proxy(**[request](#authenticatepublicappproxy-propertydetail-request)**​) Authenticates requests coming to the app from Shopify app proxies. ### Parameters * **request** **Request** **required** ### Returns * **Promise\** ### AppProxyContext * admin No session is available for the shop that made this request. Therefore no methods for interacting with the GraphQL / REST Admin APIs are available. ```ts undefined ``` * liquid A utility for creating a Liquid Response. ```ts LiquidResponseFunction ``` * session No session is available for the shop that made this request. This comes from the session storage which \`shopifyApp\` uses to store sessions in your database of choice. ```ts undefined ``` * storefront No session is available for the shop that made this request. Therefore no method for interacting with the Storefront API is available. ```ts undefined ``` ### LiquidResponseFunction * body ```ts string ``` * initAndOptions ```ts number | (ResponseInit & Options) ``` Response ```ts Response ``` ### Options * layout Whether to use the shop's theme layout around the Liquid content. ```ts boolean ``` ### AppProxyContextWithSession * admin Methods for interacting with the GraphQL / REST Admin APIs for the store that made the request. ```ts AdminApiContext ``` * liquid A utility for creating a Liquid Response. ```ts LiquidResponseFunction ``` * session The session for the shop that made the request. This comes from the session storage which \`shopifyApp\` uses to store sessions in your database of choice. Use this to get shop or user-specific data. ```ts Session ``` * storefront Method for interacting with the Shopify Storefront Graphql API for the store that made the request. ```ts StorefrontContext ``` ### AdminApiContext * graphql Methods for interacting with the Shopify Admin GraphQL API ```ts GraphQLClient ``` ### GraphQLClient * query ```ts Operation extends keyof Operations ``` * options ```ts GraphQLQueryOptions ``` interface Promise\ { /\*\* \* Attaches callbacks for the resolution and/or rejection of the Promise. \* @param onfulfilled The callback to execute when the Promise is resolved. \* @param onrejected The callback to execute when the Promise is rejected. \* @returns A Promise for the completion of which ever callback is executed. \*/ then\(onfulfilled?: ((value: T) => TResult1 | PromiseLike\) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike\) | undefined | null): Promise\; /\*\* \* Attaches a callback for only the rejection of the Promise. \* @param onrejected The callback to execute when the Promise is rejected. \* @returns A Promise for the completion of the callback. \*/ catch\(onrejected?: ((reason: any) => TResult | PromiseLike\) | undefined | null): Promise\; }, interface Promise\ {}, Promise: PromiseConstructor, interface Promise\ { readonly \[Symbol.toStringTag]: string; }, interface Promise\ { /\*\* \* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The \* resolved value cannot be modified from the callback. \* @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). \* @returns A Promise for the completion of the callback. \*/ finally(onfinally?: (() => void) | undefined | null): Promise\; } ```ts interface Promise { /** * Attaches callbacks for the resolution and/or rejection of the Promise. * @param onfulfilled The callback to execute when the Promise is resolved. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; /** * Attaches a callback for only the rejection of the Promise. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of the callback. */ catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; }, interface Promise {}, Promise: PromiseConstructor, interface Promise { readonly [Symbol.toStringTag]: string; }, interface Promise { /** * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The * resolved value cannot be modified from the callback. * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). * @returns A Promise for the completion of the callback. */ finally(onfinally?: (() => void) | undefined | null): Promise; } ``` ### GraphQLQueryOptions * apiVersion The version of the API to use for the request. ```ts ApiVersion ``` * headers Additional headers to include in the request. ```ts Record ``` * signal An optional AbortSignal to cancel the request. ```ts AbortSignal ``` * tries The total number of times to try the request if it fails. ```ts number ``` * variables The variables to pass to the operation. ```ts ApiClientRequestOptions["variables"] ``` ### StorefrontContext * graphql Method for interacting with the Shopify Storefront GraphQL API If you're getting incorrect type hints in the Shopify template, follow \[these instructions]\(https://github.com/Shopify/shopify-app-template-react-router/tree/main#incorrect-graphql-hints). ```ts GraphQLClient ``` Examples ### Examples * #### Authenticate and fetch product information ##### Description Authenticate and fetch product information ##### /app/routes/\*\*.ts ```typescript import type {LoaderFunctionArgs} from 'react-router'; import {authenticate} from '../shopify.server'; export const loader = async ({request}: LoaderFunctionArgs) => { const {storefront, liquid} = await authenticate.public.appProxy(request); if (!storefront) { return new Response(); } const response = await storefront.graphql( `#graphql query productTitle { products(first: 1) { nodes { title } } }`, ); const body = await response.json(); const title = body.data.products.nodes[0].title; return liquid(`Found product ${title} from {{shop.name}}`); }; ``` * #### Interacting with the Admin API ##### Description Use the \`admin\` object to interact with the admin GraphQL API. ##### app/routes/\*\*\\/.ts ```typescript import { json } from "react-router"; import { authenticate } from "../shopify.server"; export async function action({ request }: ActionFunctionArgs) { const { admin } = await authenticate.public.appProxy(request); const response = await admin.graphql( `#graphql mutation populateProduct($input: ProductInput!) { productCreate(input: $input) { product { id } } }`, { variables: { input: { title: "Product Name" } } } ); const productData = await response.json(); return ({ data: productData.data }); } ``` * #### Rendering liquid content ##### Description Use the \`liquid\` helper to render a \`Response\` with Liquid content using the shop's theme. See the \[Liquid reference]\(https://shopify.dev/docs/api/liquid) for all the features it enables. ##### /app/routes/\*\*\\/\*.ts ```typescript import {authenticate} from "~/shopify.server" export async function loader({ request }) { const {liquid} = await authenticate.public.appProxy(request); return liquid("Hello {{shop.name}}"); } ``` * #### Rendering liquid content without a layout ##### Description Set the \`layout\` option to \`false\` to render the Liquid content without a theme. ##### /app/routes/\*\*\\/\*.ts ```typescript import {authenticate} from "~/shopify.server" export async function loader({ request }) { const {liquid} = await authenticate.public.appProxy(request); return liquid( "Hello {{shop.name}}", { layout: false } ); } ``` * #### Rendering a form in a Liquid response ##### Description Handle form submissions through an app proxy. ##### app/routes/apps.proxy.my-action.tsx ```typescript import { redirect } from "react-router"; import { authenticate } from "~/shopify.server"; export async function loader({ request }) { const { liquid } = await authenticate.public.appProxy(request); return liquid(`
`); } export async function action({ request }) { await authenticate.public.appProxy(request); const formData = await request.formData(); const field = formData.get("field")?.toString(); // Perform actions here if (field) { console.log("Field:", field); } // Return to the form page return redirect("/apps/proxy/my-action"); } ``` * #### Using the session object ##### Description Get the session for the shop that initiated the request to the app proxy. ##### app/routes/\*\*\\/.ts ```typescript import { json } from "react-router"; import { authenticate } from "../shopify.server"; import { getMyAppModelData } from "~/db/model.server"; export const loader = async ({ request }) => { // Get the session for the shop that initiated the request to the app proxy. const { session } = await authenticate.public.appProxy(request); // Use the session data to make to queries to your database or additional requests. return ( await getMyAppModelData({shop: session.shop}) ); }; ``` * #### Interacting with the Storefront API ##### Description Use the \`storefront\` object to interact with the GraphQL API. ##### app/routes/\*\*\\/.ts ```typescript import { json } from "react-router"; import { authenticate } from "../shopify.server"; export async function action({ request }: ActionFunctionArgs) { const { storefront } = await authenticate.public.appProxy(request); const response = await storefront.graphql( `#graphql query blogIds { blogs(first: 10) { edges { node { id } } } }` ); return (await response.json()); } ``` ## Related [Interact with the Admin API. - Admin API context](https://shopify.dev/docs/api/shopify-app-react-router/apis/admin-api) [Interact with the Storefront API. - Storefront API context](https://shopify.dev/docs/api/shopify-app-react-router/apis/storefront-api) [Use the shop's theme to render a template. - Liquid reference](https://shopify.dev/docs/api/liquid)