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

Claude Code

$ npx -y skills add mrmarufpro/shopify-embedded-app-verify --skill run-embedded-app-verify --agent claude-code

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
@mrmarufpro
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

42 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
4
Star history of mrmarufpro/shopify-embedded-app-verify on GitHub, a chart by star-history.com

More skills from other plugins.

api-review

api-review

Produce the "Playwright 1.xx API Review" artifact for a range of commits - the public API additions and the breaking or behavior…

@microsoft@microsoftInstall Skill
add-e2e-selectors

add-e2e-selectors

Add reliable @grafana/e2e-selectors to interactive elements and key containers in the Grafana frontend. Use when adding e2e…

grafana5d78k
@grafana@grafanaInstall Skill
promptfoo-evals

promptfoo-evals

Write, refine, run, and QA promptfoo evaluation suites: promptfooconfig.yaml, prompts, providers, vars, tests, assertions,…

promptfoo13d27k
@promptfoo@promptfooInstall Skill
deepeval

deepeval

DeepEval evaluation workflow for AI agents and LLM applications. TRIGGER when the user wants to evaluate or improve an AI agent,…

@confident-ai@confident-aiInstall Skill

Questions about run-embedded-app-verify.

Which coding agents can use run-embedded-app-verify?
run-embedded-app-verify installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.