--- title: Unauthenticated storefront description: >- Allows interacting with the Storefront API when working outside of Shopify requests. This enables apps to integrate with 3rd party services and perform background tasks. > Caution: > This function doesn't perform **any** validation and shouldn't rely on raw user input. When using this function, consider the following: #### Background tasks Apps should ensure that the shop domain is authenticated when enqueueing jobs. #### 3rd party service requests Apps must obtain the shop domain from the 3rd party service in a secure way. api_version: v1 latest api_name: shopify-app-react-router source_url: html: >- https://shopify.dev/docs/api/shopify-app-react-router/latest/unauthenticated/unauthenticated-storefront md: >- https://shopify.dev/docs/api/shopify-app-react-router/latest/unauthenticated/unauthenticated-storefront.md --- # Unauthenticated storefront Allows interacting with the Storefront API when working outside of Shopify requests. This enables apps to integrate with 3rd party services and perform background tasks. Caution This function doesn't perform **any** validation and shouldn't rely on raw user input. When using this function, consider the following: #### Background tasks Apps should ensure that the shop domain is authenticated when enqueueing jobs. #### 3rd party service requests Apps must obtain the shop domain from the 3rd party service in a secure way. ## unauthenticated.​storefront([shop](#unauthenticatedstorefront-propertydetail-shop)​) Creates an unauthenticated Storefront context. ### Parameters * shop string required ### Returns * Promise\ ### UnauthenticatedStorefrontContext * session The session for the given shop. This comes from the session storage which \`shopifyApp\` uses to store sessions in your database of choice. This will always be an offline session. You can use this to get shop specific data. ```ts Session ``` * storefront Method for interacting with the Shopify GraphQL Storefront API for the given store. ```ts StorefrontContext ``` ````ts export interface UnauthenticatedStorefrontContext { /** * The session for the given shop. * * This comes from the session storage which `shopifyApp` uses to store sessions in your database of choice. * * This will always be an offline session. You can use this to get shop specific data. * * @example * Using the offline session. * Get your app's shop-specific data using the returned offline `session` object. * ```ts * // app/routes/**\/.ts * import { LoaderFunctionArgs, json } from "react-router"; * import { unauthenticated } from "../shopify.server"; * import { getMyAppData } from "~/db/model.server"; * * export const loader = async ({ request }: LoaderFunctionArgs) => { * const shop = getShopFromExternalRequest(request); * const { session } = await unauthenticated.storefront(shop); * return (await getMyAppData({shop: session.shop})); * }; * ``` */ session: Session; /** * Method for interacting with the Shopify GraphQL Storefront API for the given store. * * @example * Querying the GraphQL API. * Use `storefront.graphql` to make query / mutation requests. * ```ts * // app/routes/**\/.ts * import { json } from "react-router"; * import { authenticate } from "../shopify.server"; * * export async function action({ request }: ActionFunctionArgs) { * const shop = getShopFromExternalRequest(request); * const { storefront } = await unauthenticated.storefront(shop); * * const response = await storefront.graphql(`{blogs(first: 10) { edges { node { id } } } }`); * * return (await response.json()); * } * ``` * * @example * Handling GraphQL errors. * Catch `GraphqlQueryError` errors to see error messages from the API. * ```ts * // /app/routes/**\/*.ts * import { ActionFunctionArgs } from "react-router"; * import { authenticate } from "../shopify.server"; * * export const action = async ({ request }: ActionFunctionArgs) => { * const shop = getShopFromExternalRequest(request); * const { storefront } = await unauthenticated.storefront(shop); * * try { * const response = await storefront.graphql( * `#graphql * query incorrectQuery { * products(first: 10) { * nodes { * not_a_field * } * } * }`, * ); * * return ({ data: await response.json() }); * } catch (error) { * if (error instanceof GraphqlQueryError) { * // { errors: { graphQLErrors: [ * // { message: "Field 'not_a_field' doesn't exist on type 'Product'" } * // ] } } * return ({ errors: error.body?.errors }, { status: 500 }); * } * return ({ message: "An error occurred" }, { status: 500 }); * } * } * ``` * * ```ts * // /app/shopify.server.ts * import { shopifyApp } from "@shopify/shopify-app-react-router/server"; * * const shopify = shopifyApp({ * // ... * }); * export default shopify; * export const unauthenticated = shopify.unauthenticated; * ``` */ storefront: StorefrontContext; } ```` ### 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 ``` ````ts export interface StorefrontContext { /** * 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). * * {@link https://shopify.dev/docs/api/storefront} * * @example * Querying the GraphQL API. * Use `storefront.graphql` to make query / mutation requests. * ```ts * // app/routes/**\/.ts * 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(`{blogs(first: 10) { edges { node { id } } } }`); * * return (await response.json()); * } * ``` * * @example * Handling GraphQL errors. * Catch `GraphqlQueryError` errors to see error messages from the API. * ```ts * // /app/routes/**\/*.ts * import { ActionFunctionArgs } from "react-router"; * import { authenticate } from "../shopify.server"; * * export const action = async ({ request }: ActionFunctionArgs) => { * const { storefront } = await authenticate.public.appProxy(request); * * try { * const response = await storefront.graphql( * `#graphql * query incorrectQuery { * products(first: 10) { * nodes { * not_a_field * } * } * }`, * ); * * return ({ data: await response.json() }); * } catch (error) { * if (error instanceof GraphqlQueryError) { * // { errors: { graphQLErrors: [ * // { message: "Field 'not_a_field' doesn't exist on type 'Product'" } * // ] } } * return ({ errors: error.body?.errors }, { status: 500 }); * } * return ({ message: "An error occurred" }, { status: 500 }); * } * } * ``` * * ```ts * // /app/shopify.server.ts * import { shopifyApp } from "@shopify/shopify-app-react-router/server"; * * const shopify = shopifyApp({ * // ... * }); * export default shopify; * export const authenticate = shopify.authenticate; * ``` */ graphql: 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; } ``` ```ts < Operation extends keyof Operations, >( query: Operation, options?: GraphQLQueryOptions, ) => 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"] ``` ```ts export interface GraphQLQueryOptions< Operation extends keyof Operations, Operations extends AllOperations, > { /** * The variables to pass to the operation. */ variables?: ApiClientRequestOptions['variables']; /** * The version of the API to use for the request. */ apiVersion?: ApiVersion; /** * Additional headers to include in the request. */ headers?: Record; /** * The total number of times to try the request if it fails. */ tries?: number; /** * An optional AbortSignal to cancel the request. */ signal?: AbortSignal; } ``` Examples ### Examples * #### Using the offline session ##### Description Get your app's shop-specific data using the returned offline \`session\` object. ##### app/routes/\*\*\\/.ts ```typescript import { LoaderFunctionArgs, json } from "react-router"; import { unauthenticated } from "../shopify.server"; import { getMyAppData } from "~/db/model.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const shop = getShopFromExternalRequest(request); const { session } = await unauthenticated.storefront(shop); return (await getMyAppData({shop: session.shop})); }; ``` * #### Querying the GraphQL API ##### Description Use \`storefront.graphql\` to make query / mutation requests. ##### app/routes/\*\*\\/.ts ```typescript import { json } from "react-router"; import { authenticate } from "../shopify.server"; export async function action({ request }: ActionFunctionArgs) { const shop = getShopFromExternalRequest(request); const { storefront } = await unauthenticated.storefront(shop); const response = await storefront.graphql(`{blogs(first: 10) { edges { node { id } } } }`); return (await response.json()); } ``` * #### Handling GraphQL errors ##### Description Catch \`GraphqlQueryError\` errors to see error messages from the API. ##### /app/routes/\*\*\\/\*.ts ```typescript import { ActionFunctionArgs } from "react-router"; import { authenticate } from "../shopify.server"; export const action = async ({ request }: ActionFunctionArgs) => { const shop = getShopFromExternalRequest(request); const { storefront } = await unauthenticated.storefront(shop); try { const response = await storefront.graphql( `#graphql query incorrectQuery { products(first: 10) { nodes { not_a_field } } }`, ); return ({ data: await response.json() }); } catch (error) { if (error instanceof GraphqlQueryError) { // { errors: { graphQLErrors: [ // { message: "Field 'not_a_field' doesn't exist on type 'Product'" } // ] } } return ({ errors: error.body?.errors }, { status: 500 }); } return ({ message: "An error occurred" }, { status: 500 }); } } ``` ##### /app/shopify.server.ts ```typescript import { shopifyApp } from "@shopify/shopify-app-react-router/server"; const shopify = shopifyApp({ // ... }); export default shopify; export const unauthenticated = shopify.unauthenticated; ``` ## Related [Interact with the Storefront API. - API context](https://shopify.dev/docs/api/shopify-app-react-router/apis/storefront-api)