{"skill":{"slug":"shopify-link-checkout","displayName":"Shopify Link Checkout","summary":"Autonomous Shopify purchasing using Stripe Link for payment and Playwright for browser checkout. Search products across all Shopify merchants, generate one-t...","description":"---\nname: shopify-link-checkout\ndescription: |\n  Autonomous Shopify purchasing using Stripe Link for payment and Playwright for browser checkout.\n  Search products across all Shopify merchants, generate one-time payment cards via Stripe Link,\n  and complete checkout end-to-end with headless browser automation.\n  Use when: \"buy me X\", \"order X to my house\", \"purchase X from Shopify\", \"shop for X\",\n  or any request to find and buy a product from an online store.\n  Requires: Stripe Link CLI authenticated, Shopify Catalog API credentials, Playwright with Chromium.\n---\n\n# Shopify + Link Autonomous Checkout\n\nBuy products from any Shopify store using Stripe Link for payment and Playwright for browser checkout.\n\n## Prerequisites\n\n### Stripe Link CLI\n```bash\nnpm install -g @stripe/link-cli\nlink-cli auth login --client-name \"YourAgent\" --format json\n```\nUser approves at the returned `verification_url`. Backup credentials from `~/.config/link-cli-nodejs/config.json`.\n\n### Shopify Catalog API\nGet credentials at [dev.shopify.com/dashboard](https://dev.shopify.com/dashboard) → Catalogs → Get API key.\nStore `CLIENT_ID` and `CLIENT_SECRET` in your env.\n\n### Playwright + Chromium\n```bash\nnpm install playwright\nnpx playwright install chromium\n```\nIf missing system libs (headless server), download Debian packages manually and set `LD_LIBRARY_PATH`. See `references/chromium-deps.md`.\n\n## Workflow\n\n### Step 1: Find the Product\n\n**Option A — Catalog API** (search across all Shopify merchants):\n```bash\n# Get auth token (60min TTL)\nTOKEN=$(curl -s -X POST https://api.shopify.com/auth/access_token \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"client_id\":\"'$CLIENT_ID'\",\"client_secret\":\"'$CLIENT_SECRET'\",\"grant_type\":\"client_credentials\"}' \\\n  | jq -r .access_token)\n\n# Search\ncurl -s -X POST https://catalog.shopify.com/api/ucp/mcp \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"id\":1,\n    \"params\":{\"name\":\"search_catalog\",\"arguments\":{\n      \"meta\":{\"ucp-agent\":{\"profile\":\"https://shopify.dev/ucp/agent-profiles/examples/2026-04-08/valid-with-capabilities.json\"}},\n      \"catalog\":{\"query\":\"YOUR SEARCH QUERY\",\"filters\":{\"ships_to\":{\"country\":\"US\"},\"available\":true}}\n    }}\n  }'\n```\nResponse includes `variants[].id`, `variants[].seller.domain`, `variants[].price`, and `variants[].checkout_url`.\n\n**Option B — Direct store lookup** (known store):\n```\nGET https://{store-domain}/products/{handle}.json\n```\nReturns variant IDs and prices.\n\n### Step 2: Create Link Spend Request\n\n```bash\nlink-cli spend-request create \\\n  --payment-method-id \"<PAYMENT_METHOD_ID>\" \\\n  --amount <AMOUNT_IN_CENTS> \\\n  --context \"<DESCRIPTION_OF_PURCHASE>\" \\\n  --merchant-name \"<STORE_NAME>\" \\\n  --merchant-url \"<STORE_URL>\" \\\n  --request-approval \\\n  --format json\n```\n\n- Amount should cover product + tax + shipping (estimate generously)\n- Context must be 100+ chars describing the purchase (user reads this when approving)\n- Send the returned `approval_url` to the user\n\nList payment methods: `link-cli payment-methods list --format json`\n\n### Step 3: User Approves\n\nPoll for approval:\n```bash\nlink-cli spend-request retrieve <ID> --interval 2 --max-attempts 150 --format json\n```\n\n### Step 4: Get One-Time Card\n\n```bash\nlink-cli spend-request retrieve <ID> --include card --format json\n```\nReturns: `card.number`, `card.exp_month`, `card.exp_year`, `card.cvc`, `card.billing_address`.\n\n### Step 5: Run Checkout\n\n```bash\nexport LD_LIBRARY_PATH=\"<path-to-chromium-deps>\"  # if needed\nnode scripts/shopify-checkout.mjs <store-domain> <variant-id> <card-number> <MM/YY> <cvc> \\\n  --email <email> --first <name> --last <name> \\\n  --address \"<street>\" --apt \"<unit>\" --city \"<city>\" --state <ST> --zip <zip> \\\n  --phone <phone>\n```\n\nSee `scripts/shopify-checkout.mjs` for the full automation script.\n\n## Key Technical Details\n\n### Cart Permalink Bypass\nAlways use `https://{domain}/cart/{variantId}:1` to enter checkout. This bypasses Cloudflare bot detection that blocks direct `/checkout` navigation.\n\n### Checkout Types\nShopify has two checkout layouts:\n- **Single-page**: Email, address, shipping, payment all visible. Common on newer stores.\n- **Multi-step**: Information → Shipping → Payment. Must click \"Continue\" between steps.\n\nDetect by checking for `button:has-text(\"Continue to shipping\")` on page load.\n\n### Address Entry\nUse `pressSequentially()` with the full address including city to trigger Shopify's autocomplete, then click the `[role=\"option\"]` suggestion. This properly validates the address. Plain `fill()` may not trigger validation events.\n\n### Phone Numbers\nSome stores require phone. Always use `pressSequentially()`, never `fill()`. Never use fake numbers (555-xxxx) — stores validate them. Then `Tab` to blur the field.\n\n### Card PCI Iframes\nShopify checkout uses isolated PCI-compliant iframes for card entry:\n- `number-ltr` → `#number` (card number)\n- `expiry-ltr` → `#expiry` (MM/YY format)\n- `verification_value-ltr` → `#verification_value` (CVC)\n- `name-ltr` → `#name` (cardholder name)\n\nAccess via `page.frames().find(f => f.url().includes('number-ltr'))`.\n\n### Modal Popups\nSome stores show Shop Pay / login modals on checkout load. Dismiss with:\n```js\nawait page.keyboard.press('Escape');\nawait page.evaluate(() => {\n  document.querySelectorAll('[data-type=\"modal\"]').forEach(el => el.remove());\n});\n```\n\n### The Click IS the Purchase\nOnce \"Pay now\" is clicked, the order is placed server-side immediately. The browser redirect to `/thank_you` may lag or fail in headless mode. Don't treat missing confirmation page as failure — check email instead.\n\n## Error Handling\n\n| Error | Cause | Fix |\n|-------|-------|-----|\n| Cloudflare \"Just a moment...\" | Bot detection | Use cart permalink, not /checkout |\n| \"Enter a phone number\" | Required field or fake number | Use real phone with pressSequentially |\n| \"Issue processing payment\" | Card declined or expired | Create fresh Link spend request |\n| \"Checkout system error\" | Shopify infra issue or rate limit | Wait and retry |\n| Modal intercepts clicks | Shop Pay popup | Dismiss with Escape + remove via JS |\n| Card frames not found | Multi-step checkout, not at payment step yet | Navigate through steps first |\n\n## References\n\n- `scripts/shopify-checkout.mjs` — Full checkout automation script\n- `references/chromium-deps.md` — Installing Chromium on headless servers without root\n- [Stripe Link for Agents](https://link.com/agents) — Link CLI docs\n- [Shopify Agentic Commerce](https://shopify.dev/docs/agents) — Catalog + Cart + Checkout MCP\n- [Link skill.md](https://link.com/skill.md) — Official Link CLI skill reference\n","tags":{"latest":"1.0.0"},"stats":{"comments":0,"downloads":355,"installsAllTime":13,"installsCurrent":0,"stars":0,"versions":1},"createdAt":1777578535913,"updatedAt":1779076185620},"latestVersion":{"version":"1.0.0","createdAt":1777578535913,"changelog":"- Initial release of autonomous Shopify purchasing using Stripe Link and Playwright.\n- Search products across all Shopify merchants or directly from a specific store.\n- Generate one-time payment cards via Stripe Link CLI, with user approval workflow.\n- Complete end-to-end checkout on any Shopify store using headless browser automation.\n- Includes robust error handling, address autofill, proper phone validation, and modal dismissal techniques.\n- Designed for requests like \"buy me X\" or \"order X from Shopify\", requiring necessary authentication and environment setup.","license":"MIT-0"},"metadata":null,"owner":{"handle":"sdliriano","userId":"s174bq5n0khsaaw7d76rn0r59h83jdw3","displayName":"Stephen","image":"https://avatars.githubusercontent.com/u/41870969?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1780090726030}}