Programmatically Checking a Shopify App Embed with Remix
How do we, as Shopify app developers, confirm programmatically that our theme app embed is truly switched on? Shopify provides a toggle in the theme editor, but there’s no official “Check if embed is active” endpoint. For all we know, the merchant could have disabled our block—or never enabled it—in their main theme.
In this tutorial, we’ll walk through a practical solution using Remix:
- We’ll query the store’s main theme
- Retrieve and parse
settings_data.json
(while stripping out comment blocks) - Verify that our embed block isn’t set to
disabled: true
By the end, we’ll be able to confirm—directly from our code—that the app embed is actually running for every merchant who installs it.
Context
If the Embed Is Off
Merchants end up with a “half-installed” app. That can lead to confusion or missing features
No Direct “Check Embed” Endpoint
Shopify doesn’t offer /is-embed-enabled
, so we must verify—manually—that the block is disabled: false
in the main theme.
The Remix + GraphQL Approach
We’ll fetch and parse settings_data.json
, strip out comment blocks, and check if our block is enabled. This gives us a simple boolean: if true
, it’s disabled; if false
, it’s active.
Requirements & Setup
Note: Ensure your app has
read_themes
scope (andwrite_themes
if you plan on modifying theme files).
Steps in a Nutshell
1.Identify the store’s main theme.
2.Fetch and parse settings_data.json
.
3.Check if our app embed block is marked disabled: false
.
With that covered, let’s jump right into the code!
Step-by-Step Solution
4.1 Identify the Main Theme
Query All Themes
We call Shopify’s Admin API (GraphQL) to retrieve a list of themes. Only one theme should have role: MAIN
, which is the published or currently live theme.
Extract id
Once we find the main theme, we’ll grab its id
(e.g., gid://shopify/OnlineStoreTheme/123456789
). This will be crucial for the next step when we fetch settings_data.json
.
const GET_THEMES = `
query {
themes(first: 20) {
edges {
node {
id
role
name
}
}
}
}
`;
export async function getMainThemeId(admin: any) {
const response = await admin.graphql(GET_THEMES);
const responseJson = await response.json();
const themes = responseJson.data.themes.edges;
const mainTheme = themes.find((t: any) => t.node.role === "MAIN");
return mainTheme ? mainTheme.node.id : undefined;
}
4.2 Fetch settings_data.json
Use the Theme ID
With the ID from above, we craft another query to specifically retrieve settings_data.json
from that theme’s files.
Strip Comment Blocks
settings_data.json
often contains a multi-line comment (the big /* ... */
at the top). We remove it before parsing, because it breaks JSON.parse
.
Parse the JSON
After removing the comment block, convert the remainder into a JavaScript object so we can inspect the blocks.
const GET_THEME_FILE = `
query getThemeFile($id: ID!) {
theme(id: $id) {
files(filenames: ["config/settings_data.json"], first: 1) {
nodes {
filename
body {
... on OnlineStoreThemeFileBodyText {
content
}
}
}
}
}
}
`;
export async function getSettingsData(admin: any, themeId: string) {
const response = await admin.graphql(GET_THEME_FILE, { variables: { id: themeId } });
const result = await response.json();
const rawContent = result.data.theme.files.nodes[0]?.body?.content ?? "";
const cleaned = rawContent.replace(/\/\*[\s\S]*?\*\//, ""); // remove multi-line comment
return JSON.parse(cleaned);
}
4.3 Check for Your App Embed Block
Locate the "blocks"
Inside the parsed JSON, we typically look at parsedData.current.blocks
.
Find the Block Matching Your App
The block type
might look like shopify://apps/dev-storelock/blocks/country-blocking/....
Use something like block.type.includes("dev-storelock")
(or your own app handle) to confirm it’s yours.
Verify disabled
If disabled
is false
, that means the embed is actually enabled. If the block is missing or set to disabled: true
, the embed is off.
export function isAppEmbedDisabled(parsedData: any, appHandle: string): boolean {
const blocks = parsedData?.current?.blocks;
if (!blocks) return true; // If no blocks exist, treat as disabled.
// Loop over block keys
for (const blockId of Object.keys(blocks)) {
const block = blocks[blockId];
if (block?.type?.includes(appHandle)) {
return block.disabled === true;
}
}
// If we never found our block, assume disabled.
return true;
}
4.4 Putting It All Together (Remix Loader Example)
Below is a skeletal Remix loader showing how we might fetch both the main theme and then settings_data.json
, and finally check if the app embed is active:
import { json } from "@remix-run/node";
import type { LoaderFunction } from "@remix-run/node";
// Utility functions from above
import { getMainThemeId, getSettingsData, isAppEmbedDisabled } from "~/lib/shopify.server";
export const loader: LoaderFunction = async ({ request }) => {
// auth, create `admin` client, etc. omitted for brevity
const themeId = await getMainThemeId(admin);
let embedDisabled = true; // default to "embed off"
if (themeId) {
const settingsData = await getSettingsData(admin, themeId);
embedDisabled = isAppEmbedDisabled(settingsData, "dev-storelock");
}
return json({ embedDisabled });
};
In our Remix route, we end up with a simple boolean embedDisabled
. Our React component can conditionally render a warning or skip certain features if the embed is off.
Recap
Find main theme → fetch
settings_data.json
→ strip comment → check blocktype
anddisabled
.Once we have that result, we can react accordingly in our UI or logs. That’s how we confirm, programmatically, that our Shopify embed is truly enabled—no guesswork needed.
Want the Full Snippet?
For a consolidated version of all these steps, check out the Gist:
https://gist.github.com/Tommydemian/fe5896c66b5cba6b5b4a5139362758df
Happy coding and don't forget to leave a star if the code is useful, thanks!
Conclusion & Next Steps
This is a little guidance on how to integrate a working solution into a Remix environment. This tutorial covers the gap left by Shopify’s lack of a direct endpoint. With a short Remix loader (or custom hook—which I personally prefer, given my strong React background—and a bit of parsing), we get a clean, reliable way to verify the app embed’s status—no guesswork required.
Workflow Recap:
1.Locate the main theme
2.Fetch settings_data.json
3.Strip out comment blocks
4.Check the type
and disabled
fields
By following these steps, our block is truly active in the storefront—essential if the app handles security or other high-priority features.
Optional Enhancements:
Alerts: Consider logging a warning or showing a banner in your admin UI if the embed is off.
Caching: If you frequently call the Shopify Admin API, think about caching
settings_data.json
to avoid repeated fetches.
If you have questions or tips, feel free to share them in the comments.
Happy coding!
Top comments (0)