---
title: App proxy
description: >-
  App proxies take requests to Shopify links, and redirect them to external
  links.
api_version: v4
source_url:
  html: >-
    https://shopify.dev/docs/api/shopify-app-remix/latest/authenticate/public/app-proxy
  md: >-
    https://shopify.dev/docs/api/shopify-app-remix/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 | AppProxyContextWithSession>**

### AppProxyContext

* admin

  No session is available for the shop that made this request. Therefore no methods for interacting with the GraphQL Admin API 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)
  ```

returns

```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 Admin API 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
  unknown
  ```

* storefront

  Method for interacting with the Shopify Storefront Graphql API for the store that made the request.

  ```ts
  StorefrontContext
  ```

### AdminApiContext

Provides utilities that apps can use to make requests to the Admin API.

* graphql

  Methods for interacting with the Shopify Admin GraphQL API

  ```ts
  GraphQLClient<AdminOperations>
  ```

### GraphQLClient

* query

  ```ts
  Operation extends keyof Operations
  ```

* options

  ```ts
  GraphQLQueryOptions<Operation, Operations>
  ```

returns

```ts
interface Promise<T> {
    /**
     * 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<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

    /**
     * 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<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}, interface Promise<T> {}, Promise: PromiseConstructor, interface Promise<T> {
    readonly [Symbol.toStringTag]: string;
}, interface Promise<T> {
    /**
     * 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<T>;
}
```

### GraphQLQueryOptions

* apiVersion

  The version of the API to use for the request.

  ```ts
  unknown
  ```

* headers

  Additional headers to include in the request.

  ```ts
  Record<string, any>
  ```

* 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<Operation, Operations>
  ```

### StorefrontContext

Provides utilities that apps can use to make requests to the Storefront API.

* 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-remix/tree/main#incorrect-graphql-hints).

  ```ts
  GraphQLClient<StorefrontOperations>
  ```

Examples

### Examples

* ####

  ##### Description

  Authenticate and fetch product information

  ##### /app/routes/\*\*.ts

  ```ts
  import type {LoaderFunctionArgs} from '@remix-run/node';

  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}}`);
  };
  ```

* ####

  ##### Description

  Use the \`admin\` object to interact with the admin GraphQL API.

  ##### app/routes/\*\*\\/.ts

  ```ts
  import { json } from "@remix-run/node";
  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 json({ data: productData.data });
  }
  ```

* ####

  ##### 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

  ```ts
  import {authenticate} from "~/shopify.server"

  export async function loader({ request }) {
    const {liquid} = await authenticate.public.appProxy(request);

    return liquid("Hello {{shop.name}}");
  }
  ```

* ####

  ##### Description

  Set the \`layout\` option to \`false\` to render the Liquid content without a theme.

  ##### /app/routes/\*\*\\/\*.ts

  ```ts
  import {authenticate} from "~/shopify.server"

  export async function loader({ request }) {
    const {liquid} = await authenticate.public.appProxy(request);

    return liquid(
      "Hello {{shop.name}}",
      { layout: false }
    );
  }
  ```

* ####

  ##### Description

  Handle form submissions through an app proxy.

  ##### app/routes/apps.proxy.my-action.tsx

  ```ts
  import { redirect } from "@remix-run/node";
  import { authenticate } from "~/shopify.server";

  export async function loader({ request }) {
    const { liquid } = await authenticate.public.appProxy(request);

    return liquid(`
      <form method="post" action="/apps/proxy/my-action">
        <input type="text" name="field" />
        <button type="submit">Submit</button>
      </form>
    `);
  }

  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");
  }
  ```

* ####

  ##### Description

  Get the session for the shop that initiated the request to the app proxy.

  ##### app/routes/\*\*\\/.ts

  ```ts
  import { json } from "@remix-run/node";
  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 json(
      await getMyAppModelData({shop: session.shop})
    );
  };
  ```

* ####

  ##### Description

  Use the \`storefront\` object to interact with the GraphQL API.

  ##### app/routes/\*\*\\/.ts

  ```ts
  import { json } from "@remix-run/node";
  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 json(await response.json());
  }
  ```

***

## Related

[Interact with the Admin API. - Admin API context](https://shopify.dev/docs/api/shopify-app-remix/v4/apis/admin-api)

[Interact with the Storefront API. - Storefront API context](https://shopify.dev/docs/api/shopify-app-remix/v4/apis/storefront-api)

[Use the shop's theme to render a template. - Liquid reference](https://shopify.dev/docs/api/liquid)

***
