Purpose
Find a product satisfying the caller's criteria on Amazon.com, resolve its opaque ASIN from search results, verify the product detail page, add it to the shopping cart, and return confirmation data. When the caller explicitly requests replacement, inspect the active cart after adding the new item and delete the specified old item using Amazon's cart DOM controls.
When to Use
- Add a product matching a natural-language request to the Amazon.com cart.
- Requests involving capacity, product type, technology exclusions, brand, price, or similar criteria.
- Requests to replace an existing cart item with a newly selected product.
- Any flow where the caller does not already provide an ASIN.
Workflow
- Use one stealthed browser session with a US residential proxy on every call:
{ "proxy": { "proxy": "residential", "proxyCountry": "us" } }Warm https://www.amazon.com/ first in that same session, then navigate directly to the encoded search URL. Use + for spaces and optionally add i=electronics:
https://www.amazon.com/s?k={url-encoded-query}&i=electronicsUse a query containing the requested capacity, product class, and exclusions, such as {query}. Wait for div[data-component-type="s-search-result"], then resolve candidates with this evaluator:
(() => {
const intnum = (s) => {
if (!s) return null;
const m = String(s).replace(/[^0-9]/g, "");
return m ? parseInt(m, 10) : null;
};
const num = (s) => {
if (!s) return null;
const m = String(s).replace(/[^0-9.]/g, "");
return m ? parseFloat(m) : null;
};
const out = [],
seen = new Set();
for (const c of document.querySelectorAll(
'div[data-component-type="s-search-result"][data-asin]',
)) {
const asin = c.dataset.asin;
if (
!asin ||
seen.has(asin) ||
c.matches('[data-component-type="sp-sponsored-result"]') ||
c.querySelector(
'.puis-sponsored-label-text,.s-sponsored-label-text,[aria-label*="Sponsored"]',
)
)
continue;
const img = c.querySelector("img.s-image"),
h2 = c.querySelector("h2"),
p = c.querySelector(".a-price:not(.a-text-price) .a-offscreen"),
r = c.querySelector(".a-icon-alt");
let reviewCount = null;
for (const e of c.querySelectorAll("[aria-label]")) {
const a = e.getAttribute("aria-label");
if (/^[\d,]+\s+ratings?$/i.test(a)) {
reviewCount = intnum(a);
break;
}
}
seen.add(asin);
out.push({
asin,
title:
(img?.alt || "").replace(/^Sponsored Ad\s*-\s*/i, "").trim() ||
h2?.innerText?.trim() ||
null,
price: p?.textContent?.trim() || null,
priceValue: num(p?.textContent),
rating: r?.innerText?.trim() || null,
reviewCount,
url: `https://www.amazon.com/dp/${asin}`,
});
}
return JSON.stringify({ results: out });
})();Select a non-sponsored candidate satisfying every constraint. For exclusions such as “not SSD,” reject titles or visible attributes identifying SSD, solid-state, flash, or another excluded technology. Never guess an ASIN; read it from the matching search card.
Navigate directly to
https://www.amazon.com/dp/{asin}in the same session. Verify the title, capacity, product type, and exclusions on the detail page before adding. If needed, append?th=1to select the default variation. Wait for#add-to-cart-buttonorinput#add-to-cart-button, then click the visible add-to-cart control. Do not click Buy Now.Confirm the add operation with a compact evaluator on the resulting page:
(() => {
const body = document.body.innerText || "";
const count =
document.querySelector("#nav-cart-count")?.textContent?.trim() || null;
const confirmation = /added to (your )?cart|added to basket/i.test(body);
const asin = (location.pathname.match(/\/dp\/([A-Z0-9]{10})/i) || [])[1] || null;
return JSON.stringify({
success: confirmation || !!count,
added: confirmation,
asin,
cartCount: count,
url: location.href,
});
})();If there is no confirmation, inspect the add control and retry it once.
- If replacement was requested, navigate directly to
https://www.amazon.com/gp/cart/view.html, wait for active cart items, and extract them with:
(() => {
const seen = new Set(),
items = [];
for (const el of document.querySelectorAll(
'div[data-name="Active Items"] div[data-asin],div.sc-list-item[data-asin],[data-itemtype="active"] [data-asin]',
)) {
const asin = el.getAttribute("data-asin");
if (!asin || seen.has(asin)) continue;
const title = el.querySelector(
".sc-product-title,.a-truncate-cut,[class*=item-title],.sc-grid-item-product-title",
),
price = el.querySelector(
".sc-product-price,.a-price .a-offscreen,[class*=price]",
),
qty = el.querySelector(
"input[name=quantity],.sc-quantity-textfield,[data-quantity]",
);
if (title || price) {
seen.add(asin);
items.push({
asin,
title: title?.innerText.trim().replace(/\s+/g, " ") || null,
price: price?.innerText.trim().replace(/\s+/g, " ") || null,
qty: qty ? (qty.value || qty.innerText || "").trim() : null,
container: el.tagName.toLowerCase(),
});
}
}
const sub = document.querySelector(
'#sc-subtotal-amount-activecart,#sc-subtotal-amount-buybox,[data-name="Subtotal"]',
);
return JSON.stringify({
subtotal: sub?.innerText.trim() || null,
itemCount: items.length,
items,
});
})();Identify the old item by the caller's replacement description, title, or ASIN. Within that item's container, use the cart delete control input[data-action="delete-active"] and click it. If the container itself is a nested [data-asin] node, locate its nearest active-item ancestor before searching for the delete input. Wait for the cart to update, then rerun the cart evaluator and verify that the new ASIN remains active and the old item is absent. If no replacement was requested, skip deletion.
- Return the selected product, add confirmation, cart count, active items, and any replacement-deletion result. If Amazon blocks the session, stop and report the Robot Check or CAPTCHA.
Site-Specific Gotchas
- Amazon search and product URLs are frequently bot-walled for cold or datacenter sessions. Warm
https://www.amazon.com/first in the same residential-proxy session. - Pass the identical proxy configuration on every follow-up call so cookies and the warmed browser session persist; pin
proxyCountry: "us"for the US storefront. - Search results contain sponsored placements and repeated cards. Exclude sponsored cards and deduplicate by
data-asin. - The full product title is often in
img.s-image[alt];<h2>may contain only a shortened brand or label. - Product identifiers are opaque. Always read the selected ASIN from a matching search card before constructing
/dp/{asin}. - Amazon may expose the add control as either
#add-to-cart-buttonorinput#add-to-cart-button; never use#buy-now-button. - A product can have multiple variations. Verify the selected capacity and type on the detail page; append
?th=1only when needed. - Do not treat the cart icon alone as proof. Verify confirmation text, cart count, or active-cart ASINs.
- For replacement, add the new item before deleting the old one, then verify both the new item's presence and the old item's absence. The cart delete control observed for active items is
input[data-action="delete-active"]. - Cart pages may expose multiple nested
[data-asin]elements. Deduplicate ASINs and only emit records with a title or price element. - Avoid
snapshotor whole-page dumps on Amazon search/cart pages; use targeted evaluators. - If Amazon presents a Robot Check or CAPTCHA, stop and report the block rather than repeatedly navigating.
Expected Output
{
"success": true,
"asin": "{resolved-asin}",
"title": "{selected-product-title}",
"url": "https://www.amazon.com/dp/{resolved-asin}",
"added": true,
"replaced": true,
"removedAsin": "{old-asin-or-null}",
"cartCount": "{count}",
"items": [],
"error": null
}For a normal add without replacement, use replaced: false and removedAsin: null. If no matching item is found, return success: false, asin: null, added: false, and an explanatory error. If Amazon blocks the session, return success: false, added: false, and an error identifying the Robot Check or CAPTCHA.