DEV Community

Cover image for How to compare all sellers of one Allegro product by price and condition in Python
Norbert Sobala
Norbert Sobala

Posted on

How to compare all sellers of one Allegro product by price and condition in Python

Allegro groups offers for the same item under one catalogue product page. That page is where sellers fight on price, and it is also where a quick glance misleads you: new units, ex-display stock, used phones and damaged ones all sit in one list. If you do repricing or keep an eye on distributors, you want that list as a table you can filter.

This guide uses the Allegro Price Comparison actor on Apify. You paste a product or offer link and it returns every seller offer for that product. I ran it this morning on one product, the black iPhone 15 256 GB, and every number below comes from that run.

Allegro Price Comparison dataset for iPhone 15 256 GB

What the run returned

Input was a single product URL with topNOffers set to 25. The log reported 57 offers on the product page, and the actor returned 22 offer rows in 33 seconds.

A few things stood out once the data was in a table:

  • Prices ran from 1,359 PLN to 2,999.90 PLN, with a median of 2,119 PLN.
  • Only one of the 22 offers was listed as new (Stan: Nowy), at 2,999.90 PLN. Ten were used, eight were ex-display ("Powystawowy"), two were seller-refurbished and one was marked as damaged.
  • The cheapest row (1,359 PLN) was the damaged unit. The cheapest used phone was 1,400 PLN.
  • 21 of 22 offers had Allegro Smart!, and only one carried the Lowest Price Guarantee badge.
  • Two of the top three rows were promoted listings.

So the "lowest price" for this product, which the actor also reports as lowestPriceForProduct: 1359, is a damaged phone. If you compare your own new stock against that number, your repricing rule will do something silly. Grouping by condition fixes it, and the Python section shows how.

Fields you get

With outputFormat: "offers" you get one row per seller offer. The most useful columns:

Field What it holds Example from the run
offerRank Position in the product's offer list 1
title Offer title as the seller wrote it Smartfon Apple iPhone 15 6 GB / 256 GB 5G czarny
price Item price 2999.9
priceWithDelivery Price plus cheapest delivery 3010.39
deliveryFrom Cheapest delivery cost 10.49
deliveryTime Delivery estimate shown on Allegro dostawa jutro
smart Allegro Smart! eligible true
lowestPriceGuarantee "Gwarancja najniższej ceny" badge true
promoted Sponsored placement false
superSeller Super Seller badge true
sellerRating Positive feedback percentage 95.7
sellerIsCompany Business seller flag true
parameters Offer parameters such as condition and warranty {"Stan": "Nowy", "Gwarancja": "12 miesięcy"}
productRating, productReviewsCount Catalogue product rating 4.79, 106
lowestPriceForProduct Lowest price on the product page 1359
url, offerId, scrapedAt Offer link, ID and timestamp

There are also seller identifier fields (sellerLogin, sellerId, sellerUrl). In this run every seller was flagged as a company, but on a marketplace you can still hit private sellers, so the screenshots here leave those columns out and the Python example drops them before export.

With outputFormat: "products" you instead get one record per product with an offers[] array plus lowestPrice, highestPrice, avgPrice and offerCount. That suits dashboards. For analysis I prefer the flat version.

Input options

Allegro Price Comparison input form

  • productUrls: product links (/produkt/...) or offer links (/oferta/...), one per line. If you paste an offer link, the actor finds the catalogue product behind it. Allegro.pl, .cz and .sk all work.
  • topNOffers: how many offers to return per product, 1 to 500, default 20.
  • sortBy: price-asc, price-desc or rating-desc.
  • smartFilter: all offers, Smart! only, or no Smart!.
  • includePromoted: switch off to drop sponsored offers.
  • detectHiddenDiscounts: for offers with the Lowest Price Guarantee badge, it reveals the price the seller actually set and the discount Allegro applies on top (realSellerPrice, hiddenDiscount). Charged per checked offer, so leave it off unless you need it.
  • onlyChanges and monitorId: monitoring mode. Each run returns only new offers and offers whose price moved since the last run, with previousPrice and priceChange. Unchanged offers are not charged.

Option 1: no code

  1. Open the actor page and click Try for free.
  2. In the Input tab paste your product links. The iPhone 15 link is prefilled if you just want to look.
  3. Set "Top N offers per product" and pick "One row per offer" as output format.
  4. Click Start. My single-product run took about half a minute.
  5. Open the Output tab and export to Excel, CSV or JSON.

In Excel, add a filter on the parameters column and look at one condition at a time. That alone gives you a far more honest price spread than the product page does.

Option 2: Python with pandas

Install the client and pandas:

pip install apify-client pandas openpyxl
Enter fullscreen mode Exit fullscreen mode

Then run the actor and summarise by condition:

from apify_client import ApifyClient
import pandas as pd

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "productUrls": [
        "https://allegro.pl/produkt/smartfon-apple-iphone-15-6-gb-256-gb-5g-czarny-b7d39356-8090-4bcf-9247-b872c5f6935a"
    ],
    "topNOffers": 25,
    "sortBy": "price-asc",
    "outputFormat": "offers",
}

run = client.actor("liveclaude/allegro-price-comparison").call(run_input=run_input)
items = client.dataset(run["defaultDatasetId"]).list_items().items
df = pd.DataFrame(items)

# Condition lives inside the parameters dict ("Stan" on Allegro.pl)
df["condition"] = df["parameters"].apply(lambda p: (p or {}).get("Stan"))

summary = (
    df.groupby("condition")["price"]
      .agg(["count", "min", "median", "max"])
      .sort_values("median")
)
print(summary)

# Organic offers only, cheapest first, with delivery included
organic = df[~df["promoted"]].sort_values("priceWithDelivery")
print(organic[["offerRank", "price", "priceWithDelivery", "condition", "smart"]].head(10))

# Drop seller identifiers before you share the file
df.drop(columns=["sellerLogin", "sellerId", "sellerUrl"], errors="ignore") \
  .to_excel("iphone15_offers.xlsx", index=False)
Enter fullscreen mode Exit fullscreen mode

On my run the summary came out like this:

condition count min median max
Uszkodzony (damaged) 1 1359.00 1359.00 1359.00
Używany (used) 10 1400.00 1949.00 2219.00
Powystawowy (ex-display) 8 1990.00 2154.00 2189.00
Odnowiony przez sprzedawcę (refurbished) 2 2156.98 2201.00 2245.02
Nowy (new) 1 2999.90 2999.90 2999.90

The gap between the median used phone and the one new offer was about 1,050 PLN. If you sell new units, the useful benchmark is the "Nowy" row, and with only one new offer in the top 25 you would raise topNOffers to see more of them.

Scheduling and integrations

For competitor tracking, turn on onlyChanges, give the watch list a monitorId such as competitors-iphone, and add a daily Schedule in Apify Console. Each run then returns only new offers and price changes. From there you can push results to Google Sheets, Slack, Make, Zapier or n8n, or pull them over the Apify API. The actor can also be called from AI agents through the Apify MCP server.

Pricing

The actor is pay per event. Current prices per 1,000 events:

Event Free plan Business plan
Seller offer scraped $2.00 $1.50
Product compared $8.00 $6.00

Starter and Scale plans fall in between. My run had 22 offer events, so at Free plan prices the offers cost about $0.044. Hidden discount detection is billed separately per checked offer.

Responsible use

The actor reads publicly visible listing data. Keep request volumes reasonable, respect Allegro's terms, and treat any seller identifiers as potential personal data under GDPR: drop or pseudonymise them unless you have a clear reason to store them. Use the output for price analysis, not for contacting individual sellers.

This tutorial was written with AI assistance and checked by the author. All numbers come from a real run of the scraper.

Top comments (0)