Skip to content
Testing
Skill

/run-embedded-app-verify

Verify a Shopify embedded-app change by driving the real, authenticated Shopify admin in the developer's browser. Use after changing app code when the user asks to verify, check, or test the change in the browser/admin, or asks to run the verify loop.

From plugin
shopify-embedded-app-verify
42 skills1 MCP
Install
$ npx -y skills add mrmarufpro/shopify-embedded-app-verify --skill run-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/run-embedded-app-verify

Context preview

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

Verify a Shopify embedded-app change by driving the real, authenticated Shopify admin in the developer's browser. Use after changing app code when the user asks to verify, check, or test the change in the browser/admin, or asks to run the verify loop.

SKILL.md

run-embedded-app-verify.SKILL.md
name: run-embedded-app-verify
description: Verify a Shopify embedded-app change by driving the real, authenticated Shopify admin in the developer's browser. Use after changing app code when the user asks to verify, check, or test the change in the browser/admin, or asks to run the verify loop.

Verify an embedded Shopify app change in the real admin

Closed loop: preflight → dedicated verify window → navigate the embedded app → interact → assert against the plan → report. On mismatch: fix the code and loop.

Hard rules:

  • The dev server is the developer's responsibility. NEVER start it, and NEVER

probe it — do not curl the `application_url` from `shopify.app.toml` or any tunnel URL: `shopify app dev` mints a fresh tunnel URL per run, so the toml value may not be the one actually serving. Judge dev-server health only by what the app iframe renders (step 4). If it is down, tell the user and stop.

  • NEVER touch browser tabs other than the verify tab you created. The rest of

the browser belongs to the developer.

  • Delete every screenshot you take once the report is delivered (see step 6).

1. Load project config

Read `.claude/shopify-verify.json` in the project root:

{ "appHandle": "...", "storeDomain": "...", "iframeSelector": "iframe[name=\"app-iframe\"]" }

If the file is missing, run the `setup-embedded-app-verify` skill flow first (same plugin), then continue.

2. Preflight

1. Determine the verification URL first — the preflight opens the browser directly on it when it has to launch one: `https://admin.shopify.com/store/<storeDomain>/apps/<appHandle>/<page-path>` (`<page-path>` = the app route relevant to the change being verified). 2. Run:

   node ${CLAUDE_PLUGIN_ROOT}/scripts/ensure-browser.mjs --browser "${user_config.browser}" --mode "${user_config.mode}" --port "${user_config.cdp_port}" --url "<the verification URL>"

(The `${user_config.*}` values are substituted into this skill at load time; blank or literal placeholders are fine — the script defaults to chrome / profile / 9222.)

  • Exit 0 → CDP is live. Note the `BROWSER_STATE:` line in the output —

`launched-at-url`, `launched`, or `reused` — step 3 branches on it.

  • Non-zero → show the script's stderr message to the user verbatim and stop.

(`CDP_BLOCKED_DEFAULT_PROFILE` means: tell the user to switch the plugin's mode option to "profile" via /plugin → configure. `BROWSER_MISMATCH` means: a browser other than the configured one owns the CDP port — the user must quit it or change the browser/cdp_port option.) Do NOT probe the dev server or any tunnel URL here (hard rule above) — the app iframe render in step 4 is the only dev-server health check.

3. Open the verify window

Keep the developer's windows untouched.

**Preflight said `BROWSER_STATE: launched-at-url`** (profile mode): the browser opened directly at the verification URL — its only tab IS the verify window. `browser_tabs` (action: list), select that tab, grab its targetId with `browser_run_code_unsafe`, and skip to step 4:

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). `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 the verification URL.

**Case B — any non-blank tabs exist** (attach mode / browser already in use): open a dedicated verify window directly at the verification URL — no `about:blank` hop — 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: "<the verification URL above>",
    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 a tab open on the same admin page.

**In all cases: save the targetId — step 6 closes the window with it.** Every subsequent navigation/interaction happens in this tab only.

4. Drive the app

1. The verify window already loads the verification URL from step 3 — wait for it. On later loop iterations, reload / `browser_navigate` this same tab instead of opening a new window. 2. If the URL redirects to `accounts.shopify.com`: the Shopify session expired.

  • attach mode → ask the user to log into the Shopify admin in their browser, wait, retry.
  • profile mode → leave the verify window open on the login page, ask the user

to log in there once, wait for their confirmation, retry. 3. Wait for the app iframe (`iframeSelector` from config), then take an iframe-scoped `browser_snapshot`. If it shows a tunnel/connection error instead of the app UI — "server IP address could not be found", `ERR_NAME_NOT_RESOLVED`, `ERR_CONNECTION_REFUSED`, a Cloudflare tunnel error page (e.g. error 1033), or a bare "can't be reached" page — the app's dev server is not running or not reachable. Report exactly that to the user, ask them to check that their

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