Home / Blog / Amazon Listing Audit via API: Compare Your Listing with the Top Competitors

Amazon Listing Audit via API: Compare Your Listing with the Top Competitors

Audit an Amazon listing against the listings that rank for its keyword: check the title against Amazon's January 2025 title rules and compare images, bullet points, video, A+ content and ratings with the top five organic results - seven credits per audit, in Python.

September 30, 2026
5 min read
SellerMagnet Team
Share & Bookmark
Blueprint flow from a keyword through search and product lookups to title checks, competitor medians and findings

An Amazon listing audit compares your product page with the listings that already win your main keyword. /api/amazon-search returns the first results page; /api/amazon-product-lookup returns each listing's title, bullet points, images, videos, A+ content flag and ratings. The script below checks your title against Amazon's January 2025 title rules and flags where your listing has fewer images, bullet points or ratings than the top five organic results, or lacks the video or A+ content most of them have - seven credits per audit.

Key Takeaways

  • An audit against five competitors costs seven credits: one search and one lookup per listing.
  • Sponsored results are skipped, so the benchmark is the listings that rank organically for the keyword.
  • Amazon's title rules since January 21, 2025: at most 200 characters in most categories, no ! $ ? _ { } ^ ¬ ¦ outside a brand name, no word more than twice except prepositions, articles and conjunctions.
  • Image, bullet and ratings counts are compared with the competitors' median; video and A+ content with how many competitors have them.
  • The lookup reports at most two videos, and its A+ flag is also true for a brand story or product documents.

What should an Amazon listing audit check?

Two kinds of things: rules and gaps. Rules come from Amazon - since January 21, 2025, a title may not exceed 200 characters in most categories, may not contain the characters ! $ ? _ { } ^ ¬ ¦ unless they are part of the brand name, and may not repeat a word more than twice; prepositions, articles and conjunctions are exempt. Gaps come from your competitors: fewer images, fewer bullet points, no video or no A+ content where most of them have it.

What the script checks, the lookup field behind it and when it raises a finding.
CheckFieldFinding when
Title lengthtitleOver 200 characters
Special characterstitle! $ ? _ { } ^ ¬ ¦ outside the brand
Repeated wordstitleA word more than twice
KeywordtitleA keyword word is missing
ImagesimagesFewer than the competitor median
Bullet pointsbulletPointsFewer than the competitor median
VideovideosNone, while most competitors have one
A+ contenthasAPlusContentNone, while most competitors have it
Ratingsreviews.totalReviewsFewer than the competitor median

How do I audit a listing against competitors in Python?

Search the keyword, look up your listing and the first five organic results, then compare. audit() turns one lookup into the numbers above; findings() applies the title rules and the competitor medians and prints your own position for the keyword. A competitor whose lookup fails is skipped and the next organic result takes its place, up to two times; a 401 or 403 stops the run. get_with_retry() comes from retry.py, new_session() and ApiError from sellermagnet.py in the Python quickstart.

listing_audit.py - your listing against the top five organic results

"""Listing audit: your listing against the top organic results for your main keyword."""
import re
import statistics
import sys

import requests

from retry import get_with_retry
from sellermagnet import ApiError, new_session

MARKETPLACE, KEYWORD, YOUR_ASIN = "ATVPDKIKX0DER", "playstation 5 slim", "B0CL61F39H"
COMPETITORS = 5
BANNED = set("!$?_{}^¬¦")                       # Amazon title rules (Jan 2025): allowed only in a brand name
SMALL_WORDS = {"a", "an", "the", "and", "or", "but", "nor", "so", "yet", "than", "for", "with", "without", "of",
               "in", "on", "at", "to", "by", "from", "as", "into", "per", "over", "under", "up", "about",
               "between", "through", "after"}   # English; the rule exempts prepositions, articles, conjunctions


def words(text: str) -> list[str]:
    return [w for w in re.findall(r"[^\W_]+", text.lower()) if len(w) > 1 and not w.isdigit()]


def audit(p: dict) -> dict:
    title = p.get("title") or ""
    counted = [w for w in words(title) if w not in SMALL_WORDS]
    bullets = p.get("bulletPoints") or []
    reviews = p.get("reviews") or {}
    return {"asin": p.get("asin"), "title_chars": len(title), "bullets": len(bullets),
            "images": len(p.get("images") or []), "video": bool(p.get("videos")),
            "a_plus": bool(p.get("hasAPlusContent")), "rating": reviews.get("averageRating"),
            "ratings": reviews.get("totalReviews") or 0,
            "banned_chars": "".join(sorted(BANNED & set(title))),
            "repeated": sorted({w for w in counted if counted.count(w) > 2}),
            "missing_keywords": [w for w in dict.fromkeys(words(KEYWORD)) if w not in words(title)]}


def findings(you: dict, rivals: list[dict]) -> list[str]:
    out = []
    if you["title_chars"] > 200:
        out.append(f"title has {you['title_chars']} characters: most categories allow 200")
    if you["banned_chars"]:
        out.append(f"title contains {you['banned_chars']}: allowed only as part of the brand name")
    if you["repeated"]:
        out.append(f"title repeats {', '.join(you['repeated'])} more than twice")
    if you["missing_keywords"]:
        out.append(f"title lacks the keyword word(s) {', '.join(you['missing_keywords'])}")
    for key, label in (("images", "images"), ("bullets", "bullet points"), ("ratings", "ratings")):
        values = [r[key] for r in rivals if key != "ratings" or r[key]]   # 0 ratings can be an unread count
        median = statistics.median_low(values) if values else None
        if median is not None and you[key] < median:
            out.append(f"{label}: {you[key]:,} vs a median of {median:,} among the top {len(rivals)}")
    for key, label in (("video", "video"), ("a_plus", "A+ content")):
        have = sum(r[key] for r in rivals)
        if not you[key] and have > len(rivals) / 2:
            out.append(f"no {label}: {have} of {len(rivals)} competitors have it")
    return out


def lookup(session, asin: str) -> dict:
    p = get_with_retry(session, "amazon-product-lookup", asin=asin, marketplaceId=MARKETPLACE)
    return audit(p["productInfo"])


if __name__ == "__main__":
    session = new_session()
    try:
        results = get_with_retry(session, "amazon-search", q=KEYWORD, marketplaceId=MARKETPLACE,
                                 count=20)["searchResults"]
        you = lookup(session, YOUR_ASIN)
    except (ApiError, requests.RequestException) as err:
        sys.exit(f"stopped: {err}")                  # e.g. a 404 on YOUR_ASIN
    rivals, failed = [], 0
    for asin in dict.fromkeys(r.get("asin") for r in results if not r.get("sponsored")):
        if len(rivals) == COMPETITORS or failed == 2:
            break
        if asin and asin != YOUR_ASIN:
            try:
                rivals.append(lookup(session, asin))
            except (ApiError, requests.RequestException) as err:
                if getattr(err, "status", None) in (401, 403):
                    sys.exit(f"stopped: {err}")      # key or credits: every further call fails too
                failed += 1                          # the next organic result takes its place
    position = next((r.get("position") for r in results if r.get("asin") == YOUR_ASIN and not r.get("sponsored")),
                    None)
    print(f"your position for '{KEYWORD}': {position or 'not among the priced results on page 1'}")
    for r in [you, *rivals]:
        print(f"{r['asin']}  title {r['title_chars']:>3}  bullets {r['bullets']}  images {r['images']:>2}  "
              f"video {'yes' if r['video'] else 'no ':<3}  A+ {'yes' if r['a_plus'] else 'no ':<3}  "
              f"{r['rating'] or '-'} ({r['ratings']:,})")
    print("\n".join(f"- {f}" for f in findings(you, rivals)) if rivals
          else f"no competitors to compare ({failed} lookups failed)")

Audit output (illustrative data; your title is deliberately broken)

your position for 'playstation 5 slim': 2
B0CL61F39H  title 208  bullets 3  images  4  video no   A+ no   4.6 (1,200)
B0RIVAL001  title  22  bullets 5  images  7  video yes  A+ yes  4.7 (5,400)
B0RIVAL002  title  17  bullets 5  images  6  video yes  A+ yes  4.5 (3,100)
B0RIVAL004  title  18  bullets 5  images  8  video yes  A+ yes  4.8 (9,800)
B0RIVAL005  title  18  bullets 5  images  5  video no   A+ yes  4.4 (800)
B0RIVAL006  title  17  bullets 4  images  7  video yes  A+ yes  4.6 (4,100)
- title has 208 characters: most categories allow 200
- title contains !: allowed only as part of the brand name
- title repeats console, gaming more than twice
- images: 4 vs a median of 7 among the top 5
- bullet points: 3 vs a median of 5 among the top 5
- ratings: 1,200 vs a median of 4,100 among the top 5
- no video: 4 of 5 competitors have it
- no A+ content: 5 of 5 competitors have it

For a quick look at one listing - yours or a competitor's - jq prints the same counts from a single lookup.

Title length, bullets, images, video and A+ for one listing

curl -sG "https://sellermagnet-api.com/api/amazon-product-lookup" \
  -H "X-Api-Key: $SELLERMAGNET_API_KEY" --max-time 120 \
  --data-urlencode "asin=B0CL61F39H" \
  --data-urlencode "marketplaceId=ATVPDKIKX0DER" \
  | jq -r 'if .success then .data.productInfo
           | "title \(.title | length) chars, \(.bulletPoints | length) bullets, \(.images | length) images, video: \((.videos // []) | length > 0), A+: \(.hasAPlusContent)"
           else error(.message) end'
Blueprint bar chart of the number of images on your listing and on five competing listings
Illustrative: four images against a competitor median of seven.

Which competitors should the benchmark use?

The listings that rank organically for the keyword that matters most to you. The search reads the first results page only and skips products without a displayed price; sponsored results are marked and left out, because an ad position says little about the listing itself. Run the audit for two or three keywords when your product sells under different names - the keyword rank tracking guide shows where you rank for each.

Blueprint table of the nine listing checks, the lookup field each reads and when it raises a finding
Three title rules from Amazon, a keyword check and five gaps against competitors.

What the audit cannot judge

  • Image quality. The lookup lists image URLs, not backgrounds or resolution; the product image guide shows how to download them and check sizes.
  • The brand-name exemption. A ! in a brand name is allowed; the script flags it and you decide.
  • Other languages. The exempt small words are English, and the search marks sponsored results by their label markup, with a text fallback only in English and German; check both on other stores.
  • Counts that depend on the page. The bullet count comes from the feature bullets or, where Amazon shows it, the product-facts block; a ratings count of 0 can also mean it could not be read, so the script leaves zeros out of the median.
  • What only Seller Central shows. Backend search terms, suppressed listings, main-image compliance and Amazon's own listing quality reports are not in product data.
  • Copy quality. Counts say that a competitor has five bullet points, not that they are good ones.

Competitors change their listings too. Once the audit has shown which listings set the bar, the listing change monitor tells you when one of them changes its title, bullet points, images or A+ content.

Frequently Asked Questions

How do I audit an Amazon listing?

Check the title against Amazon's title rules, then compare images, bullet points, video, A+ content and ratings with the listings that rank organically for your main keyword.

What are Amazon's title requirements?

Since January 21, 2025: at most 200 characters in most categories, no ! $ ? _ { } ^ ¬ ¦ unless part of the brand name, and no word more than twice, except prepositions, articles and conjunctions.

How many credits does an audit cost?

Seven if every lookup succeeds: one search and six lookups. Failed attempts are billed too - a 404 once, a 502 or 503 up to four times through get_with_retry() - and each replacement competitor costs one more.

Why are sponsored results skipped?

Sponsored placements are paid for; the benchmark uses the listings Amazon ranks organically for the keyword.

Does the audit check image quality?

No. The lookup returns image URLs; background and resolution need the images themselves, which you can download and inspect.

Bottom line: one search and six lookups show whether your title follows Amazon's rules and where your listing has less than the ones that rank - fix those first. A free account includes 150 credits, enough for 21 audits.

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