---
title: "How I Taught My Agent to Shop"
date: 2026-03-18
description: "Amazon won't let AI agents browse their shelves. But they left the back door wide open — a cart URL that takes ASINs and quantities as parameters. Here's how I used Claude Code to build a one-click bill of materials for a Home Assistant appliance."
tags: ["ai-agents","ai-hacks-on-tap","home-automation"]
readingTime: "8 min read"
url: https://alexmoening.com/dev-thoughts/how-i-taught-my-agent-to-shop.html
markdownUrl: https://alexmoening.com/dev-thoughts/how-i-taught-my-agent-to-shop.md
---

# How I Taught My Agent to Shop

[← Back to /dev/thoughts](/dev-thoughts/)

<p class="lead">I needed eight components for a dedicated Home Assistant appliance — a Pi 5, an NVMe drive, a Zigbee coordinator, a UPS, and a handful of cables. My first instinct was to have my agent open a browser and add each item to a shopping list. Twenty-four acceptance criteria later, I hadn't added a single item to cart. Then I found the URL that made all of it unnecessary.</p>

### The Bill of Materials Problem

<p class="section-summary">Hardware projects generate shopping lists. Shopping lists mean tabs, comparison shopping, and the nagging suspicion you picked the wrong SSD.</p>

I've been building a dedicated Home Assistant box — a Raspberry Pi 5 with NVMe storage, battery backup, and a Zigbee coordinator. The kind of appliance that replaces a Docker container running on a NAS with something purpose-built and resilient. Eight components, six vendors considered, three hours of comparison shopping across spec sheets and Reddit threads.

My agent did the research. Claude Code helped me evaluate NVMe vs. microSD reliability data, compare Zigbee coordinator firmware options, and size a UPS that could keep a 27W Pi running through a brown-out. By the end, I had a clean bill of materials:

<table class="data-table">
    <thead>
        <tr>
            <th>Component</th>
            <th>Selection</th>
            <th>Est. Price</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Compute</td>
            <td>Raspberry Pi 5 8GB</td>
            <td>$80</td>
        </tr>
        <tr>
            <td>Storage</td>
            <td>Samsung 970 EVO Plus 250GB NVMe</td>
            <td>$45</td>
        </tr>
        <tr>
            <td>Enclosure</td>
            <td>Argon ONE V5 M.2 NVMe Case</td>
            <td>$45</td>
        </tr>
        <tr>
            <td>Zigbee</td>
            <td>Home Assistant Connect ZBT-2</td>
            <td>$49</td>
        </tr>
        <tr>
            <td>Power Protection</td>
            <td>APC Back-UPS BE425M</td>
            <td>$60</td>
        </tr>
        <tr>
            <td>Power Supply</td>
            <td>Pi 5 Official 27W USB-C PSU</td>
            <td>$12</td>
        </tr>
        <tr>
            <td>Network</td>
            <td>Cat 6 Ethernet Cable 3ft</td>
            <td>~$5</td>
        </tr>
        <tr>
            <td>Peripheral</td>
            <td>USB-A Extension Cable 6in</td>
            <td>~$5</td>
        </tr>
    </tbody>
</table>

Total: roughly $301 for a battery-backed, NVMe-equipped Home Assistant appliance with native Zigbee coordination. The research was done. Now I just needed to buy the stuff.

### The Playwright Approach (Don't Do This)

<p class="section-summary">Browser automation against e-commerce sites is fragile, adversarial, and unnecessary.</p>

My first plan was to automate Amazon with Playwright. Open a browser session, search for each ASIN, click "Add to List," screenshot the confirmation, move to the next item. I wrote a PRD with twenty-four acceptance criteria. Login detection. CAPTCHA handling. Fallback products for out-of-stock items. Screenshot verification for every step.

I never executed a single one.

The more I thought about it, the more I realized I was building a fragile robot to fight an adversarial UI. Amazon doesn't want bots on their site. They have every right to block them. And the approach was solving the wrong problem — I didn't need to *browse* Amazon, I needed to *buy from* Amazon. There's a difference.

### The Perplexity Problem

<p class="section-summary">E-commerce sites are caught between wanting AI traffic and fearing what it does to their business model.</p>

This tension isn't unique to my shopping list. It's the same conflict playing out across the entire e-commerce industry right now.

When Perplexity launched its shopping features, the reaction from retailers was immediate and hostile. The concern isn't just about scraping — it's about what happens to the business model when an AI intermediary sits between the customer and the buy button.

<table class="data-table">
    <thead>
        <tr>
            <th>Concern</th>
            <th>Why Retailers Care</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Ad impressions</td>
            <td>If an agent summarizes product pages, sponsored listings never render — the impression is fake or absent entirely</td>
        </tr>
        <tr>
            <td>Upsell surface</td>
            <td>"Frequently bought together" and "customers also viewed" disappear when an agent extracts just the target product</td>
        </tr>
        <tr>
            <td>Price comparison</td>
            <td>Agents trivially compare across retailers, compressing margins to zero</td>
        </tr>
        <tr>
            <td>Brand storytelling</td>
            <td>Product pages are designed to create desire — agents skip straight to specs and price</td>
        </tr>
        <tr>
            <td>Attribution</td>
            <td>When an agent drives a purchase, who gets credit? The agent? The prompt? The underlying model?</td>
        </tr>
    </tbody>
</table>

These are legitimate business concerns. The advertising-funded web depends on eyeballs, and agents don't have eyeballs. A bot that scrapes product data and presents it in a chat interface is genuinely destructive to the revenue model that keeps those product pages online in the first place.

But there's a version of this that works for everyone.

### The Cart URL

<p class="section-summary">Amazon already has an API for exactly this. It's a URL.</p>

Amazon's "Add to Cart" URL has been public and documented for years. The format is simple:

<pre class="terminal"><code>https://www.amazon.com/gp/aws/cart/add.html
  ?ASIN.1=B0CTQ3BQLS&Quantity.1=1
  &ASIN.2=B07MG119KG&Quantity.2=1
  &ASIN.3=B0DKWMKBK2&Quantity.3=1
  ...</code></pre>

That's it. Each `ASIN.N` parameter takes a product identifier, each `Quantity.N` sets the count. The user clicks the link, Amazon's normal cart page opens with all items pre-loaded, and the customer completes checkout through the standard flow — with all the upsells, shipping options, and payment methods intact.

No browser automation. No scraping. No CAPTCHA evasion. No adversarial relationship with the retailer. The customer still lands on Amazon, still sees the full product pages if they want to review items, still completes payment through Amazon's checkout. The retailer's funnel is preserved.

My agent's job was just to do the research, find the right ASINs, and assemble the URL.

### The Agent Workflow

<p class="section-summary">Research the components, collect ASINs, generate the URL, hand it to the human.</p>

Here's what actually happened:

<table class="data-table">
    <thead>
        <tr>
            <th>Step</th>
            <th>What the Agent Did</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Research components</td>
            <td>Compare NVMe vs. microSD failure rates, evaluate Zigbee coordinator options, size UPS capacity against Pi 5 power draw</td>
        </tr>
        <tr>
            <td>Select specific products</td>
            <td>Match requirements to specific Amazon listings with verified ASINs</td>
        </tr>
        <tr>
            <td>Generate the cart URL</td>
            <td>Concatenate ASINs and quantities into the add-to-cart URL format</td>
        </tr>
        <tr>
            <td>Document alternatives</td>
            <td>List backup ASINs for out-of-stock items — different Pi 5 listing, white vs. black PSU, dual-NVMe case variant</td>
        </tr>
        <tr>
            <td>Create pre-purchase checklist</td>
            <td>Verify form factor, firmware version, plug type, bundle vs. single unit</td>
        </tr>
    </tbody>
</table>

The output was a markdown document with the one-click URL at the top, individual product links in a table below, alternative ASINs for out-of-stock items, and a checklist to verify before clicking buy. The human reviews the document, clicks the link, and checks out. Thirty seconds from decision to purchase.

No Playwright. No twenty-four-step acceptance criteria. No screenshots. No login detection. No CAPTCHA handling. Just a URL.

### Why This Pattern Matters

<p class="section-summary">The best agent-commerce pattern preserves the retailer's checkout flow while letting agents handle research and assembly.</p>

This isn't just a hack for my Home Assistant build. It's a pattern that generalizes.

The agent handles what agents are good at — research, comparison, specification matching, and document assembly. The human handles what requires human judgment and authorization — reviewing the selection and completing payment. The retailer keeps what they need — the customer on their site, in their checkout flow, seeing their upsells.

<table class="data-table">
    <thead>
        <tr>
            <th>Approach</th>
            <th>Agent Value</th>
            <th>Retailer Impact</th>
            <th>Friction</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Browser automation</td>
            <td>High</td>
            <td>Hostile — bypasses ads, upsells, tracking</td>
            <td>High — CAPTCHAs, auth, UI changes break it</td>
        </tr>
        <tr>
            <td>Scraping + chat checkout</td>
            <td>High</td>
            <td>Destructive — removes customer from site entirely</td>
            <td>Medium — legal and technical barriers</td>
        </tr>
        <tr>
            <td>Cart URL assembly</td>
            <td>High</td>
            <td>Neutral to positive — customer arrives at checkout</td>
            <td>Low — public, supported, stable</td>
        </tr>
    </tbody>
</table>

The cart URL approach is the only one where everyone wins. The agent adds value. The retailer keeps the customer. The customer saves time. And nobody is fighting anybody's terms of service.

### The Bigger Picture

<p class="section-summary">E-commerce will need agent-friendly entry points. Cart URLs are the first primitive.</p>

I think we're going to see more of this. As coding assistants and personal agents become part of daily workflows, the "last mile" problem in agent-assisted purchasing is going to matter. The research phase is already solved — agents are great at comparing specs, reading reviews, and finding products. The checkout phase should remain human (at least for now — I don't want my agent authorizing purchases without me).

The gap in the middle — going from "I know what I want" to "it's in my cart" — is where patterns like Amazon's cart URL shine. It's a simple, stable, public interface that lets agents assemble purchasing intent without touching the retailer's UI.

Amazon could go further. A lightweight API that takes a list of ASINs and returns current prices, availability, and estimated delivery dates would let agents build smarter shopping lists without ever rendering a product page. The agent handles research and assembly; the human handles review and payment; the retailer handles fulfillment and relationship. Everyone stays in their lane.

For now, the cart URL is enough. I went from eight components across six browser tabs to one link and a thirty-second checkout. My agent did the hard part. I just clicked "Place Order."

<blockquote class="pull-quote">The best agent-commerce patterns don't replace the shopping experience. They compress the boring parts and hand you the buy button.</blockquote>

That Pi 5 ships Thursday.

---

## Navigation

- [Home](/)
- [About](/about.html)
- [Projects](/projects.html)
- [Contact](/contact.html)
- [/dev/thoughts](/dev-thoughts/)

*Copyright 2026 Alex Moening. Opinions expressed are my own.*
