“Handling response” message when redirecting to Theme Editor after first app install

Hey everyone,

I’m building a very simple embedded Shopify app. The flow is quite simple:

Merchant installs the app (first visit).

They see an input field for a numeric, 4 digit key (where they get it from is not important for now).

They click Save.

We store that numeric key as a shop-level metafield, then immediately redirect them into the Theme Editor → App Embeds section.

The problem:

On the very first install, when they click Save, the interface changes to “Handling response” and never redirects. After a manual browser refresh, clicking Save works perfectly—no “Handling response” hang, redirect happens immediately.

The merchant flow breaks until they reload, which is a terrible UX.

I have added a link to a google drive folder with a screen recording of the issue.

I am open to sharing a git repo with the code, as this is still a dev store, and I have gone nowhere with this problem for a while now.

Screen recording →

Hi - this could be related to how you’re using App Bridge, some actions you could try here are:

  • Use App Bridge’s Redirect action to navigate to Shopify admin URLs.
  • Ensure you initialize App Bridge with the correct host parameter (from the query string).
  • On first load, if host is missing, redirect to your app URL with the correct shop and host parameters.
  • Only attempt App Bridge redirects after confirming App Bridge is initialized.

@Liam-Shopify — thanks a lot for the feedback!

I read your response right away and have been working on it for the past hour, but I’m stuck. I see that I’m currently redirecting with a basic window.top.location.href = theme_editor_url, but I’m not sure how to properly implement App Bridge’s Redirect.

Below is a snippet from my app._index.jsx file — I’d really appreciate any guidance or example you could point me to!



import { json } from "@remix-run/node";
import { useFetcher, useLoaderData } from "@remix-run/react";
import {
  Page,
  Layout,
  Card,
  TextField,
  Button,
  BlockStack,
  Text,
} from "@shopify/polaris";
import { TitleBar } from "@shopify/app-bridge-react";
import { useState, useEffect } from "react";
import { authenticate } from "../shopify.server.js";

export const loader = async ({ request }) => {

  await authenticate.admin(request); // Ensure the Shopify session cookie is set

  return json({
    SHOPIFY_API_KEY: process.env.SHOPIFY_API_KEY,
    blockHandle: "star_rating", // Thats just the name of the app embed file we are running, will change it later
  });

};

export const action = async ({ request }) => { 
 // We are saving the metadata here, so I am going to skip this piece of code. Can share if needed, but I do not think it matters for the redirect issue
 };

export default function Index() {
  const { SHOPIFY_API_KEY, blockHandle } = useLoaderData();
  const fetcher = useFetcher();
  const [site_id, set_site_id] = useState("");
  const [error, setError]   = useState("");

  // After saving, redirect top-level into Theme Editor → App embeds
  useEffect(() => {

    if ( fetcher.data?.success ) {
      const shop = new URLSearchParams(window.location.search).get("shop");
      const theme_editor_url = `https://${shop}/admin/themes/current/editor?context=apps&activateAppId=${SHOPIFY_API_KEY}/${blockHandle}&target=newAppsSection/app-embed`;

      window.top.location.href = theme_editor_url;
    }

    if ( fetcher.data?.error ) setError(fetcher.data.error);

  }, [fetcher.data, SHOPIFY_API_KEY, blockHandle]);

  return (
    <Page>
      <TitleBar title="ST Setup Test" />
      <Layout>
        <Layout.Section>
          <Card sectioned>
            <fetcher.Form method="post">
              <BlockStack gap="loose">
                <Text as="h2" variant="headingMd">
                  Enter your site ID
                </Text>
                <TextField
                  name="site_id"
                  value={site_id}
                  onChange={set_site_id}
                  placeholder="e.g. 2339"
                />
                {error && <Text color="critical">{error}</Text>}
                <Button submit primary disabled={ ! site_id }>
                  Save
                </Button>
              </BlockStack>
            </fetcher.Form>
          </Card>
        </Layout.Section>
      </Layout>
    </Page>
  );
}

Actually redirect would be for an older version of App Bridge - instead you’d use the Navigation API to redirect within an app.

Thank you! I am looking at it right now!

I tried implementing it, but I believe the issue may be authentication, rather than redirect.

I get this error in the console


app-bridge.js:1 
            
            
           POST https://rolls-trail-binary-two.trycloudflare.com/app?index=&embedded=1&hmac=393f0718a24283ac9e8f8fa8c375c24fbe1fcef70abb1760809d3bfca262c66e&host=YWRtaW4uc2hvcGlmeS5jb20vc3RvcmUvZ2VvcmdlLXRlc3Rpbmctc3RvcmUtc3Q&id_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczpcL1wvZ2VvcmdlLXRlc3Rpbmctc3RvcmUtc3QubXlzaG9waWZ5LmNvbVwvYWRtaW4iLCJkZXN0IjoiaHR0cHM6XC9cL2dlb3JnZS10ZXN0aW5nLXN0b3JlLXN0Lm15c2hvcGlmeS5jb20iLCJhdWQiOiJkYjE2NWIwZTQxZTVjZTkwMGIwMWNhMGUxNjYwODZlNiIsInN1YiI6IjEyOTM1Nzg3MzQxNyIsImV4cCI6MTc0OTgyMzY2NywibmJmIjoxNzQ5ODIzNjA3LCJpYXQiOjE3NDk4MjM2MDcsImp0aSI6IjQ3YjQ3NmFlLWQwOWUtNDY5Yy05ZjU5LWJmNTk2NmZmOGMyYiIsInNpZCI6ImYxNmJkM2NiLTQ3YzQtNDg5Yi1hYjI5LWVhNWU4YzNjMDRlZiIsInNpZyI6ImE5NGQ3MDhkNzFjNTEwYzllMDYzZGM2ZTk5NDJkNjRmNDdlNWNkYWNjZjZiNDBlOWNiZGIzZGRkM2I0ODczN2YifQ.1m5h7dGVggCkz00yw_SXDwlZh5UDtEWtobzeZRBEFVQ&locale=en&session=10f258561603fb544a740f5372e4e8b6b10ca8bd90d004b3a14c16fb26e7047c&shop=george-testing-store-st.myshopify.com&timestamp=1749823607&_data=routes%2Fapp._index 401 (Unauthorized)

Here is a snippet of the new redirect code


export default function Index() {
  const { SHOPIFY_API_KEY, blockHandle } = useLoaderData();
  const fetcher = useFetcher();
  const [site_id, set_site_id] = useState("");
  const [error, setError]   = useState("");

  // After saving, redirect top-level into Theme Editor → App embeds
  useEffect(() => {

    if (fetcher.data?.success) {
      open(
        'shopify://admin/themes/current/editor?context=apps&activateAppId=' +
          `${SHOPIFY_API_KEY}/${blockHandle}&target=newAppsSection/app-embed`,
        '_top'
      );
    }

    if ( fetcher.data?.error ) setError(fetcher.data.error);

  }, [fetcher.data, SHOPIFY_API_KEY, blockHandle]);

  return (
    <Page>
      <TitleBar title="ST Setup Test" />
      <Layout>
        <Layout.Section>
          <Card sectioned>
            <fetcher.Form method="post">
              <BlockStack gap="loose">
                <Text as="h2" variant="headingMd">
                  Enter your site ID
                </Text>
                <TextField
                  name="site_id"
                  value={site_id}
                  onChange={set_site_id}
                  placeholder="e.g. 2339"
                />
                {error && <Text color="critical">{error}</Text>}
                <Button submit primary disabled={ ! site_id }>
                  Save
                </Button>
              </BlockStack>
            </fetcher.Form>
          </Card>
        </Layout.Section>
      </Layout>
    </Page>
  );
}

It could indeed be auth related - this doc is helpful for setting up authentication. Are you using the Remix template generated by the CLI? That should handle auth for you, without needing to set it up yourself.

Thanks, I am looking at it right now! I will let you know if I have any questions with the documentation.

Yes, I believe I am using Remix template generated by the CLI. It is a Remix app.

Hey @Liam-Shopify, I have been at this for a few hours. The documentation quite clearly says that if I have used a Shopify CLI to generate a starter app, then authentication and authorisation should be automatically handled.

Also I am struggling to make sense as to why I face this “Handling response” issue only the first time clicking on “Save”, after installing the app, and not any other time.

And I don’t think I need any access scopes for my application.