Home / Blog / Amazon Buy Box Factors: What Actually Wins, According to Amazon

Amazon Buy Box Factors: What Actually Wins, According to Amazon

Amazon's own help names the Buy Box factors: total price, the delivery promise, free shipping, free returns and seller performance. It does not consider the fulfillment method, Prime eligibility or star ratings. Check where the featured offer stands on each visible factor with two API calls per ASIN.

October 25, 2026
10 min read
SellerMagnet Team
Share & Bookmark
Terminal window with the Python function that compares the Amazon featured offer with the cheapest New offer on landed price

Amazon names the Amazon Buy Box factors itself. Its US help page on the Featured Offer, the offer in the Buy Box, lists total price (item plus shipping), the delivery promise, free shipping, free returns and seller performance. The same page says Amazon does not consider star ratings, Prime eligibility or the fulfillment method, and out-of-stock offers cannot be featured. Two API calls per ASIN show where the featured offer stands on the factors the data contains.

Key Takeaways

  • Amazon's US help names five Buy Box factors: total price including shipping, the delivery promise, free shipping, free returns and seller performance.
  • The same page rules out customer reviews and star ratings, Prime eligibility and the fulfillment method: with all other factors equal, FBA and FBM offers are equally likely to be featured.
  • Since September 2026 there is no seller eligibility requirement, but Amazon can still show no featured offer when no offer meets its customer experience requirements.
  • The offers data covers three of the factors for every offer (totalPrice, deliveryDate, shippingPrice), with limits; free returns and seller performance are not in it.
  • A factor check costs 2 credits per ASIN when nothing fails: one offers call for the live featured offer, one statistics call for 30 days of holder history.

What are the Amazon Buy Box factors, according to Amazon?

The Featured Offer is the offer with the Add to Cart and Buy Now buttons on a product page. Amazon's US Seller Central help page "Becoming the Featured Offer" says Amazon ranks qualified offers "according to the factors that customers care about most" and adds: "We rank offers the same way for every product, and we never use manual overrides to select one offer over another." When no single offer is clearly more attractive than the others, the page says, the Featured Offer could be a rotation of the best offers. The table lists the factors the page names, plus stock, and what the API returns for each: /amazon-product-offers reads the live offer listing (details on the Product Offers endpoint page).

The Featured Offer factors on Amazon's US help page and what the offers data shows of each (checked 24 October 2026).
FactorWhat Amazon's US help saysIn the API data
PriceTotal price, item plus shipping, "plays an important role"totalPrice of every offer, buyBox.totalPrice of the featured one
Delivered promiseFaster offers and a specific delivery promise, not a range, are more likely to be featureddeliveryDate, one date per offer or N/A
Free shippingOffers with free shipping are more likely to become featuredshippingPrice 0.0, also when no delivery price was shown
Free returnsFree returns can improve your chancesNot in the data
Seller performanceDimensions include order volume, chargeback rate and Voice of the Customer complaintsNot in the data
StockAn offer cannot be featured while it is out of stockoffers empty: no offers were read

Which Buy Box myths does Amazon rule out?

The same page has a section on what Amazon does not consider, and a few more lines that settle the myths sellers repeat most:

  • FBA wins the Buy Box. The fulfillment method is on the not-considered list: "If all other factors are equal, offers fulfilled by Amazon or Fulfilled by Merchant are equally likely to be featured." What counts is what the offer promises, such as a fast, specific delivery date and free shipping, whichever channel delivers it.
  • Prime offers win. Prime eligibility of the offer is on the same list. A Prime member may still see a different featured offer, because Prime-enrolled customers may see lower shipping fees or faster delivery promises.
  • Good seller ratings win. Amazon evaluates seller performance along dimensions such as order volume, chargeback rate and Voice of the Customer complaints, "not through customer-submitted seller reviews or star ratings".
  • The lowest price always wins. "Total price (item price plus shipping fee) plays an important role in determining the Featured Offer", next to the four other factors it names. Amazon's US seller blog puts it this way: "Featured Offer prices are commonly at or below the lowest priced alternatives." Commonly, not always.
  • New sellers have to qualify first. "As of September 2026, Amazon no longer maintains a seller eligibility requirement, and offers from all sellers are now eligible to be evaluated for the Featured Offer." Amazon still features no offer at all when none of the available offers meets its customer experience requirements; for that case the page points to three checks: the offer ships to the customer's location, it is in stock, and Pricing Health shows no pricing issue.
  • Every shopper sees the same Buy Box. It is determined separately for each variation, and shoppers can see a different featured offer from another shipping location or with a Prime membership.
Table of six Buy Box myths, what Amazon's US help says about each, and the API field to check
Amazon's US help lists the fulfillment method, Prime eligibility and star ratings as not considered; the right column names the field or parameter that shows each point in the API data.

How do you check the factors on your own ASINs?

Put the ASINs in asins.txt, one per line. For each ASIN the script calls /amazon-product-offers once and compares the featured offer with the other New offers on the factors in the data: the landed price against the cheapest and the delivery date against the earliest, and it shows the featured offer's shipping price. It also shows the fulfillment channel and where the seller rating stands, two signals Amazon says it does not consider. Then it calls /amazon-product-statistics once and counts the sellers that held the Buy Box in the last 30 days and the share of that time nobody did. get_with_retry comes from retry.py, and ApiError and new_session from sellermagnet.py, both published in the Python quickstart. Errors are reported per row: a 400 from the offers endpoint or a 401 or 403 from either endpoint stops the run (a parameter, key or credits problem that would repeat on every ASIN), and so do three ASINs that keep failing. A 400 from the statistics endpoint, which answers on 11 marketplaces, only leaves the history empty.

Install requests, set the key, list the ASINs, run the check

pip install requests
export SELLERMAGNET_API_KEY="your-key-here"
echo B0CL61F39H > asins.txt
python3 buybox_factors.py

buybox_factors.py: the featured offer against the other New offers, plus 30 days of holder history

"""Amazon Buy Box factor check: where the featured offer stands on the factors Amazon names, for a list of ASINs.

Amazon's US help lists the Featured Offer (Buy Box) factors: total price (item plus shipping), the delivery promise,
free shipping, free returns and seller performance. /amazon-product-offers shows the first three for every offer on
the first page of the listing, so the script compares the featured offer with the other New offers on them. It also
prints the seller rating and the channel, which Amazon says it does not consider, and reads the holder history of
/amazon-product-statistics: how many sellers held the Buy Box in the last 30 days and how long nobody did.
Helpers: sellermagnet.py and retry.py from https://sellermagnet-api.com/blog/amazon-product-api-python
"""
import re
from collections import Counter
from datetime import date, datetime, timedelta, timezone

import requests

from retry import get_with_retry
from sellermagnet import ApiError, new_session

MARKETPLACE = "ATVPDKIKX0DER"   # amazon.com; the statistics endpoint answers on 11 of the 23 marketplaces
ASIN_FILE = "asins.txt"         # one ASIN per line
WINDOW = timedelta(days=30)     # how far back the holder history is read
MAX_FAILED = 3                  # 502/503 are billed on every attempt: stop after 3 ASINs that keep failing
ROW = "{:<10}  {:<13}  {:<7}  {:<8}  {:<5}  {:<7}  {:>7}  {}"
DAY = re.compile(r"\d{4}-\d\d-\d\d")


def read_asins(path):
    keep, bad = [], []
    with open(path, encoding="utf-8-sig") as fh:   # utf-8-sig also reads a file saved with a byte order mark
        for line in fh:
            asin = line.strip().upper()
            if not asin:
                continue
            if not re.fullmatch(r"[A-Z0-9]{10}", asin):
                bad.append(asin)        # both endpoints bill a malformed ASIN, so it never leaves the script
            elif asin not in keep:
                keep.append(asin)       # each ASIN once: a repeat would cost 2 more credits
    return keep, bad


def priced_new(offer):
    """A New offer whose item price was read: an unread one has priceWithoutShipping 0.0, totalPrice = shipping."""
    return offer.get("condition") == "New" and bool(offer.get("priceWithoutShipping"))


# The featured offer against the other New offers: landed price and seller rating against the best of them,
# delivery date against the earliest.
def live_check(data):
    box = data.get("buyBox") or {}
    total = box.get("totalPrice") or 0
    if not data.get("offers"):
        return None, "no offers"
    if data.get("buyBoxSuppressed") or not total:
        return None, "no featured offer"
    if box.get("condition") != "New":
        return None, "featured offer not New"
    new = [o for o in data["offers"] if priced_new(o)]
    landed = round(total, 2)
    low = min([o["totalPrice"] for o in new] + [landed])
    gap = round(landed - low, 2)
    price = f"+{gap:.2f}" if gap > 0 else "lowest"
    days = [o["deliveryDate"] for o in new if DAY.fullmatch(str(o.get("deliveryDate")))]
    own = str(box.get("deliveryDate"))
    delivery = "n/a"
    if days and DAY.fullmatch(own):
        late = (date.fromisoformat(own) - date.fromisoformat(min(days))).days
        delivery = "earliest" if late <= 0 else f"+{late} day{'s' if late > 1 else ''}"
    mine = box.get("positivePercentage") or 0
    rating = "-"                        # Amazon's own offer and unrated sellers have positivePercentage 0
    if mine:
        best = max([o.get("positivePercentage") or 0 for o in new] + [mine])
        rating = "top" if best <= mine else f"-{best - mine} pts"
    channel = "Amazon" if box.get("sellerId") == "Amazon" else box.get("fulfillmentType", "?")
    return {"channel": channel, "featured": f"{channel} {landed:.2f}", "price": price, "delivery": delivery,
            "ship": f"{box.get('shippingPrice') or 0:.2f}", "rating": rating}, ""


# buyBoxSellerIdHistory lists changes of holder: each entry holds the Buy Box until the next one (or now).
# "-1" = nobody held the Buy Box; "-2" = a seller not identified yet, which counts as one holder.
def holder_check(history, now):
    if not history:
        return None
    changes = sorted(((datetime.strptime(ts, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc), str(who))
                      for ts, who in history), key=lambda c: c[0])
    start = max(now - WINDOW, changes[0][0])    # a history that began inside the window covers less time
    if start >= now:
        return None
    holders, nobody = set(), timedelta(0)
    for (ts, who), (until, _) in zip(changes, changes[1:] + [(now, None)]):
        begin, end = max(ts, start), min(until, now)
        if end <= begin:
            continue                    # this holder's time ended before the window opened
        if who == "-1":
            nobody += end - begin
        else:
            holders.add(who)
    return len(holders), nobody / (now - start), (now - start).days


def history(session, asin, now):
    """-> (holders, share of the time without a holder, days covered) or None, a note, and whether it failed."""
    try:
        stats = get_with_retry(session, "amazon-product-statistics", asin=asin, marketplaceId=MARKETPLACE)
    except ApiError as err:
        if err.status in (401, 403):
            raise                       # key or credits: stop the run
        return None, f"history error {err.status}", err.status >= 500   # a 400 here is free, the run goes on
    except (requests.ConnectionError, requests.Timeout) as err:
        return None, f"history error {type(err).__name__}", True
    held = holder_check(stats.get("buyBoxSellerIdHistory"), now)
    return held, "" if held else "no holder history", False


def line(asin, cells=("-",) * 6, note=""):
    return ROW.format(asin, *cells, note).rstrip()


def main():
    asins, bad = read_asins(ASIN_FILE)
    if bad:
        print("skipped, not an ASIN:", ", ".join(bad))
    session, now = new_session(), datetime.now(timezone.utc)
    print(line("asin", ("featured", "price", "delivery", "ship", "rating", "holders"), "note"))
    checks, held_all, answered, failed = [], [], 0, 0
    for asin in asins:
        if failed >= MAX_FAILED:
            print(f"stopped after {MAX_FAILED} failed ASINs")
            break
        try:
            data = get_with_retry(session, "amazon-product-offers", asin=asin, marketplaceId=MARKETPLACE)
            live, note = live_check(data)
            held, why, outage = history(session, asin, now)
        except ApiError as err:
            if err.status in (400, 401, 403):   # parameters, key or credits: every other ASIN would fail too
                print(f"stopped: {err}")
                break
            print(line(asin, note=f"error {err.status}"))
            failed += err.status != 404         # a 404 is a billed answer (no such product), not an outage
            continue
        except (requests.ConnectionError, requests.Timeout) as err:
            print(line(asin, note=f"error {type(err).__name__}"))
            failed += 1
            continue
        answered += 1
        failed += outage
        cells = [live[k] for k in ("featured", "price", "delivery", "ship", "rating")] if live else ["-"] * 5
        notes = [note, why]
        if held:
            holders, share, covered = held
            held_all.append(holders)
            notes += [f"no holder {share:.0%}" if share >= 0.005 else "",
                      f"history {covered} days" if covered < WINDOW.days else ""]
        checks += [live] if live else []
        print(line(asin, cells + [held[0] if held else "-"], ", ".join(n for n in notes if n)))

    print(f"\nfeatured offers: {len(checks)} of {answered} ASINs that answered")
    if checks:
        dated = [c for c in checks if c["delivery"] != "n/a"]
        rated = [c for c in checks if c["rating"] != "-"]
        channels = Counter(c["channel"] for c in checks)
        print(f"  at the lowest landed price: {sum(c['price'] == 'lowest' for c in checks)} of {len(checks)}")
        print(f"  with the earliest delivery date: {sum(c['delivery'] == 'earliest' for c in dated)} of {len(dated)}")
        print(f"  with the best seller rating: {sum(c['rating'] == 'top' for c in rated)} of {len(rated)} rated")
        print("  by channel:", ", ".join(f"{k} {n}" for k, n in sorted(channels.items())))
    print(f"Buy Box held by 2 or more sellers in {WINDOW.days} days: {sum(h >= 2 for h in held_all)} of "
          f"{len(held_all)} ASINs with history")


if __name__ == "__main__":
    main()

Output of buybox_factors.py on amazon.com (illustrative data, prices in USD)

skipped, not an ASIN: 4.00638E+12
asin        featured       price    delivery  ship   rating   holders  note
B0CL61F39H  Amazon 444.99  lowest   earliest  0.00   -              2
B0EXAMPLE1  FBM 24.99      +1.00    earliest  0.00   -7 pts         3
B0EXAMPLE2  FBA 19.49      lowest   +1 day    0.00   top            1
B0EXAMPLE3  FBM 39.99      +0.01    earliest  0.00   -3 pts         2
B0EXAMPLE4  -              -        -         -      -              1  no featured offer, no holder 25%
B0EXAMPLE5  -              -        -         -      -              1  no offers, no holder 20%
B0EXAMPLE6  -              -        -         -      -              -  error 404
B0EXAMPLE7  -              -        -         -      -              -  error 502

featured offers: 4 of 6 ASINs that answered
  at the lowest landed price: 2 of 4
  with the earliest delivery date: 3 of 4
  with the best seller rating: 1 of 3 rated
  by channel: Amazon 1, FBA 1, FBM 2
Buy Box held by 2 or more sellers in 30 days: 3 of 6 ASINs with history

The illustrative asins.txt had ten lines: eight ASINs, one repeated in lowercase, and 4.00638E+12, a barcode in scientific notation that never reaches the API. On B0EXAMPLE1 the featured offer is an FBM offer at 24.99, 1.00 above the cheapest New offer, an FBA offer at 23.99, but it arrives on 27 October, four days earlier, and its seller is rated 92% against 99%. B0EXAMPLE3 is Amazon's own free shipping example in numbers: the page says "a $40 offer with free shipping is preferable to a $35 offer with $5 shipping", and here 39.99 with free delivery is featured over 34.99 plus 4.99 shipping, which lands 0.01 lower. B0EXAMPLE2 goes the other way: the FBA offer is featured at the lowest price although an FBM offer arrives a day earlier. B0EXAMPLE4 has an offer but no featured offer, and nobody held the Buy Box for 25% of the last 30 days; B0EXAMPLE5 returned no offers at all.

Table of an illustrative run with the featured offer, its price, delivery and rating standing, the Buy Box holders in 30 days and a note for eight ASINs
The featured offer was the cheapest on two of four listings; on B0EXAMPLE1 it costs 1.00 more but arrives four days sooner (illustrative data).

The summary counts four featured offers, so read it as an illustration, not a market figure: run the script on your own ASINs and read each row first. Two of the four were not the cheapest offer, two came from FBM sellers, and only one of the three rated sellers had the best rating, which fits what Amazon's page says and proves nothing beyond these listings. For the size of the price gap across many listings, the Buy Box price gap guide measures the featured offer against the cheapest New offer.

Reading the offers and the holder history

This is the B0EXAMPLE1 offers response the run used, trimmed to the fields the check reads. buyBox is the featured offer, which is also offers[0], and its totalPrice is the unrounded sum of item price and shipping, so the script rounds it before comparing; in offers[] every totalPrice is already rounded to 2 decimals. positivePercentage is the seller rating (0 for Amazon's own offer and for a seller without one), and an offer whose item price could not be read has priceWithoutShipping 0.0, so the script leaves it out.

Trimmed /amazon-product-offers response for B0EXAMPLE1 (illustrative values)

{
  "data": {
    "asin": "B0EXAMPLE1",
    "buyBox": {
      "condition": "New",
      "deliveryDate": "2026-10-27",
      "fulfillmentType": "FBM",
      "positivePercentage": 92,
      "priceWithoutShipping": 24.99,
      "sellerId": "A3EXAMPLESELLR",
      "shippingPrice": 0.0,
      "totalPrice": 24.99
    },
    "buyBoxSuppressed": false,
    "offers": [
      {
        "condition": "New",
        "deliveryDate": "2026-10-27",
        "fulfillmentType": "FBM",
        "positivePercentage": 92,
        "priceWithoutShipping": 24.99,
        "sellerId": "A3EXAMPLESELLR",
        "shippingPrice": 0.0,
        "totalPrice": 24.99
      },
      {
        "condition": "New",
        "deliveryDate": "2026-10-31",
        "fulfillmentType": "FBA",
        "positivePercentage": 99,
        "priceWithoutShipping": 23.99,
        "sellerId": "A4EXAMPLESELLR",
        "shippingPrice": 0.0,
        "totalPrice": 23.99
      },
      {
        "condition": "New",
        "deliveryDate": "2026-10-29",
        "fulfillmentType": "FBM",
        "positivePercentage": 96,
        "priceWithoutShipping": 22.49,
        "sellerId": "A5EXAMPLESELLR",
        "shippingPrice": 4.49,
        "totalPrice": 26.98
      }
    ]
  },
  "success": true
}

buyBoxSellerIdHistory from /amazon-product-statistics (parameters on the Product Statistics endpoint page) lists changes of holder in UTC: each seller keeps the Buy Box until the next entry. The script counts the holders over the last 30 days, including the one who held it when the window opened, and the time marked -1, when nobody held it. -2 is a seller whose ID is not known yet, so it counts as a holder, and on amazon.com Amazon appears as ATVPDKIKX0DER, not as Amazon. The result is a share of time: the Featured Offer percentage in Seller Central's Business Reports counts page views instead, and only for your own offers. The Buy Box history guide turns the same series into a time share per seller.

Trimmed /amazon-product-statistics response for B0EXAMPLE1 (illustrative values)

{
  "data": {
    "asin": "B0EXAMPLE1",
    "buyBoxSellerIdHistory": [
      ["2026-09-12 10:00:00", "A4EXAMPLESELLR"],
      ["2026-09-30 18:30:00", "A3EXAMPLESELLR"],
      ["2026-10-11 07:05:00", "A5EXAMPLESELLR"],
      ["2026-10-13 21:45:00", "A3EXAMPLESELLR"],
      ["2026-10-19 08:00:00", "A4EXAMPLESELLR"],
      ["2026-10-21 16:20:00", "A3EXAMPLESELLR"]
    ],
    "trackingSince": "2024-03-02"
  },
  "success": true
}

Credit math for a factor check

Every request costs 1 credit, so the check costs 2 credits per ASIN when nothing fails: 100 ASINs cost 200 credits. The run above made 17 billed requests: 6 offers and 6 statistics calls for the ASINs that answered, the 404 for B0EXAMPLE6 (billed, not retried, and the script skips its statistics call) and 4 attempts for B0EXAMPLE7, which kept failing with 502; the repeat and the barcode cost nothing. A 404 is billed and not retried, 502 and 503 are billed on every attempt (up to 4 here), a 500 without a Retry-After header is refunded and retried once, and 429, 401, 403 and gate 400s are free, including the statistics endpoint's 400 on the 12 marketplaces it does not cover. MAX_FAILED stops the run after 3 ASINs that keep failing on either endpoint, so an outage costs at most 12 failed attempts. Plans and credit prices are on the pricing page.

What the data cannot show

  • Free returns and seller performance: the offers data has no return policy and no order volume, chargeback or complaint figures, so two of the five factors stay invisible.
  • A delivery range: deliveryDate holds one date per offer, so you cannot see whether Amazon showed a specific date or a range, which its help says is less likely to be featured.
  • Free shipping versus no shipping shown: shippingPrice is 0.0 in both cases.
  • Every shopper's Buy Box: one call reads one delivery location, the marketplace's default postcode unless you pass geo_location, and Prime members can see a different featured offer.
  • Every offer: one call reads the first page of the offer listing, the featured offer plus the offers Amazon loads first.
  • A sure stock-out: an empty offers list can also come from a page whose offers could not be read, so check again before you call a listing out of stock.
  • Why an offer is featured: the check shows where the featured offer stands on the visible factors; the ranking itself stays Amazon's.

Frequently Asked Questions

What are the Amazon Buy Box factors?

Amazon's US help names total price including shipping, the delivery promise, free shipping, free returns and seller performance, judged on dimensions such as order volume, chargeback rate and Voice of the Customer complaints. An offer that is out of stock cannot be featured.

Does FBA help you win the Buy Box?

Not by itself. Amazon lists the fulfillment method among the factors it does not consider: with all other factors equal, FBA and FBM offers are equally likely to be featured. Fast, specific delivery dates and free shipping count, whichever channel provides them.

Do seller ratings affect the Buy Box?

Not according to Amazon's US help. It evaluates seller performance on dimensions such as order volume, chargebacks and complaints, not through customer-submitted seller reviews or star ratings. Prime eligibility of the offer is not considered either.

Do sellers still need Buy Box eligibility?

No. As of September 2026 Amazon no longer keeps a seller eligibility requirement, and offers from all sellers are eligible to be evaluated. Amazon can still show no featured offer when no offer meets its customer experience requirements.

What does a Buy Box factor check cost in credits?

Two credits per ASIN when nothing fails: one offers call and one statistics call. A 404 is billed, 502 and 503 are billed on every attempt, a 500 without Retry-After is refunded, and 429, 401, 403 and gate 400s are free.

Bottom line: Amazon's own help names the Buy Box factors, total price, delivery promise, free shipping, free returns and seller performance, and rules out star ratings, Prime eligibility and the fulfillment method. Two API calls per ASIN show where the featured offer stands on price, delivery and shipping and whether the Buy Box changes hands; they cannot show returns, seller performance or why Amazon picked an offer.

Ready to Extract Amazon Data at Scale?

Start building with SellerMagnet API today. Real-time product data, competitive pricing, and review analytics at your fingertips.

150 free API credits • No credit card required • Cancel anytime