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.
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
-
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-descorrating-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
previousPriceandpriceChange. Unchanged offers are not charged.
Option 1: no code
- Open the actor page and click Try for free.
- In the Input tab paste your product links. The iPhone 15 link is prefilled if you just want to look.
- Set "Top N offers per product" and pick "One row per offer" as output format.
- Click Start. My single-product run took about half a minute.
- 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
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)
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)