Skip to content
Testing
Skill

/setup-embedded-app-verify

One-time setup for the Shopify embedded-app verify loop in a project. Use when the user asks to set up / configure the verify loop, or when the run-embedded-app-verify skill finds no project config.

From plugin
shopify-embedded-app-verify
42 skills1 MCP
Install
$ npx -y skills add mrmarufpro/shopify-embedded-app-verify --skill setup-embedded-app-verify --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/setup-embedded-app-verify

Context preview

The summary Claude sees to decide when to auto-load this skill.

One-time setup for the Shopify embedded-app verify loop in a project. Use when the user asks to set up / configure the verify loop, or when the run-embedded-app-verify skill finds no project config.

SKILL.md

setup-embedded-app-verify.SKILL.md
name: setup-embedded-app-verify
description: One-time setup for the Shopify embedded-app verify loop in a project. Use when the user asks to set up / configure the verify loop, or when the run-embedded-app-verify skill finds no project config.

Set up the embedded-app verify loop

Goal: a CDP-enabled, Shopify-authenticated browser plus a project config file.

1. Show the resolved developer config

The plugin config is substituted into this skill at load time:

  • browser: `${user_config.browser}`
  • mode: `${user_config.mode}`
  • cdp_port: `${user_config.cdp_port}`

A blank value (or a literal dollar-brace placeholder) means the default applies: chrome / profile / 9222. Tell the user the resolved values and that they can be changed anytime via `/plugin` → shopify-embedded-app-verify → configure (changes reach skills after `/reload-plugins` or a session restart). Do NOT read `CLAUDE_PLUGIN_OPTION_*` env vars — they are only set for plugin subprocesses such as hooks, never for Bash commands you run.

2. Ensure the browser

Run:

node ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-browser.mjs --browser "${user_config.browser}" --mode "${user_config.mode}" --port "${user_config.cdp_port}" --url "https://admin.shopify.com"

Note the `BROWSER_STATE:` line in the output — `launched-at-url`, `launched`, or `reused` — step 3 branches on it.

  • Exit 0 → continue.
  • `CDP_BLOCKED_DEFAULT_PROFILE` → explain: this browser refuses CDP on its

default profile (Chrome/Edge 136+). The user must switch the plugin's mode option to "profile" (dedicated automation profile, one-time login). Stop.

  • `BROWSER_MISMATCH` → the CDP port is already served by a browser that is

not the configured one (and not one this plugin launched). Show the message verbatim — the user must quit that browser or change the plugin's browser/cdp_port option. Stop. (A stale automation browser from an earlier run is handled automatically — the script quits it and relaunches.)

  • Other non-zero → show the message verbatim; stop.

3. Open the verify window and check Shopify authentication

Never open tabs in the developer's own windows.

**Preflight said `BROWSER_STATE: launched-at-url`** (profile mode): the browser opened directly at `https://admin.shopify.com` — its only tab IS the verify window. `browser_tabs` (action: list), select that tab, grab its targetId with `browser_run_code_unsafe`, and continue to the auth check below:

async (page) => {
  const session = await page.context().newCDPSession(page);
  const { targetInfo } = await session.send("Target.getTargetInfo");
  await session.detach();
  return targetInfo.targetId;
}

**Preflight said `BROWSER_STATE: launched` or `reused`**: the browser's tabs belong to the developer (an attach-mode relaunch restores their session — those tabs are NOT yours, whatever they show, even an admin dashboard). `browser_tabs` (action: list), then:

**Case A — the list shows only blank tabs** (`about:blank` / `chrome://new-tab-page` — a browser nobody is using): reuse that startup window instead of opening a second one. Select it, grab its targetId with `browser_run_code_unsafe`:

async (page) => {
  const session = await page.context().newCDPSession(page);
  const { targetInfo } = await session.send("Target.getTargetInfo");
  await session.detach();
  return targetInfo.targetId;
}

then `browser_navigate` it to `https://admin.shopify.com`.

**Case B — any non-blank tabs exist** (attach mode / browser already in use): open a dedicated verify window with `browser_run_code_unsafe` (the code is invoked with the current page as its single argument):

async (page) => {
  const session = await page.context().newCDPSession(page);
  const { targetId } = await session.send("Target.createTarget", {
    url: "https://admin.shopify.com",
    newWindow: true,
  });
  await session.detach();
  return targetId;
}

Then `browser_tabs` (action: list) and select the newly added entry — the tab that was not in the list before creation (new tabs are appended at the end); do not pick the first URL match, the developer may already have an admin tab open.

**In all cases: save the targetId — step 5 closes the window with it.**

  • Lands on a store dashboard (`admin.shopify.com/store/...`) → authenticated.
  • Redirects to `accounts.shopify.com` login → tell the user: "Log into the

Shopify admin in the verify window that just opened — the session persists." (profile mode: once per browser — each browser gets its own automation profile.) Wait for their confirmation, then re-check.

Keep the verify window open — the smoke test (step 5) reuses it.

4. Write the project config

1. `appHandle`: read `handle` from the project's `shopify.app.toml`. Multiple toml files (e.g. `shopify.app.<env>.toml`) → ask which one is the dev app. 2. `storeDomain`: ask the user for the dev store subdomain (`<storeDomain>.myshopify.com` → store part only, e.g. `store-seo-app-test`). 3. Write `.claude/shopify-verify.json`:

{
  "appHandle": "<from toml>",
  "storeDomain": "<from user>",
  "iframeSelector": "iframe[name=\"app-iframe\"]"
}

5. Smoke test

1. In the verify window from step 3, navigate to `https://admin.shopify.com/store/<storeDomain>/apps/<appHandle>`. 2. Wait for the app iframe; take a screenshot; confirm the app rendered.

  • 404 → the app is not installed on this store; point the user to the dev

server output's install link.

  • Iframe loads an error/tunnel page → the app's dev server is not running;

tell the user to check it (starting it is their job — never start or curl-probe it yourself). The verify loop needs it running, but setup itself is complete. 3. Report the result and delete the screenshot. 4. Close the verify window with `browser_run_code_unsafe` and the targetId saved in step 3 (never `browser_close` or close-by-index — both act on the current tab and misfire when the developer has many tabs open; if the

Read more
Ships withshopify-embedded-app-verify

A Claude Code plugin that closes the verification loop for agentic Shopify embedded-app development: the agent changes code, then drives your **real, authenticated** Shopify admin — in your own browser — to check the result against the plan, repeating until

Get the whole plugin
Stats
4
Stars
2
Forks
Maintained
Maintenance
JavaScript
Language
MIT
License
2mo ago
Last commit
2mo ago
Created

Repo: mrmarufpro/shopify-embedded-app-verify