After testing sell-through and country comparison, I wanted to check two smaller signals:
- Seller profiles.
- Exact listing price history.
Both are useful, but they are not equal.
Seller profiles are good for watchlists.
Price tracking is good for exact item URLs.
I ran both live on June 4, 2026 with Vinted Smart Scraper.
Disclosure: I built this Actor. Some Apify links may use my referral code.
๐ง Why these signals matter
Most Vinted automation starts with a broad search:
query -> results -> CSV
That is useful once.
But resellers eventually ask more specific questions:
Is this seller consistently interesting?
Did this exact item drop?
Did this watched item disappear?
Should I get alerted now or ignore it?
Those are not the same job.
That is why this part is about smaller signals.
They do not look as impressive as a big export, but they are the signals that make a scheduled workflow useful.
๐งฉ Seller profile is not item monitoring
Before the live run, I separated the workflows:
| Workflow | Best signal | Bad use |
|---|---|---|
| Seller watchlist | Seller activity and profile stats | Exact price drops |
| Price tracking | Exact item URL history | Discovering new items |
| Sell-through tracker | Query/listing disappearance | Seller reputation |
| Sold-items page | Explicit sold evidence when available | Assuming every missing item is sold |
This matters because a single "Vinted monitor" can easily become confusing.
The user should know what each mode is answering.
๐ค Run 1: seller watchlist
The seller URL came from a real SEARCH output:
{
"mode": "SELLER_PROFILE",
"sellerUrls": [
"https://www.vinted.fr/member/3146082883-adwatches"
],
"maxItems": 1,
"includePhotos": false,
"maxConcurrency": 1,
"requestDelayMs": 500
}
Live result:
| Field | Value |
|---|---|
| Run ID | qJbKKIoxK0XiPifIO |
| Dataset ID | C9v2k3RMb6C3nP3yQ |
| Status | SUCCEEDED |
| Duration | 41s |
| Rows emitted | 1 |
| Free-tier estimated charge | $0.022 |
Output:
{
"id": 3146082883,
"username": "adwatches",
"profileUrl": "https://www.vinted.fr/member/3146082883-adwatches",
"rating": 1,
"ratingCount": 11,
"itemCount": 1,
"soldItemCount": 14,
"followerCount": 3,
"country": "fr",
"lastSeenAt": "2026-06-04T22:11:32+02:00",
"verifications": {
"email": true,
"phone": false,
"facebook": false,
"google": true
}
}
๐ What this profile tells me
This row is not an "opportunity" by itself.
It is a filter.
| Field | Live value | How I use it |
|---|---|---|
rating |
1 |
Weak trust signal, inspect manually |
ratingCount |
11 |
Enough history to avoid treating it as brand new |
itemCount |
1 |
Not currently a large active inventory |
soldItemCount |
14 |
Some past sales activity |
followerCount |
3 |
Not a high-demand seller profile |
phone verified |
false |
Not a blocker, but useful context |
google verified |
true |
Basic identity signal |
For this seller, I would not build a high-frequency monitor.
I might still watch exact item URLs if the listing itself looks underpriced.
That is the point: profile data helps decide where not to spend monitoring budget.
โ When seller monitoring helps
| Question | Mode |
|---|---|
| Does this seller keep listing relevant inventory? | SELLER_PROFILE |
| Did their shop count change? | SELLER_PROFILE |
| Did watched items disappear? |
SELL_THROUGH_TRACKER with item URLs |
| Did an exact listing price drop? | PRICE_TRACK |
I would not schedule seller profile checks every 5 minutes.
Daily is usually enough unless you are monitoring a very specific seller.
๐ Seller watchlist templates
Small daily seller check:
{
"mode": "SELLER_PROFILE",
"sellerUrls": [
"https://www.vinted.fr/member/3146082883-adwatches"
],
"maxItems": 1,
"includePhotos": false,
"maxConcurrency": 1,
"requestDelayMs": 500
}
Seller shortlist after a search run:
{
"mode": "SELLER_PROFILE",
"sellerUrls": [
"https://www.vinted.fr/member/3146082883-adwatches",
"https://www.vinted.fr/member/123456-example"
],
"maxItems": 10,
"includePhotos": false
}
What I would send to Telegram:
Seller adwatches: 1 active item, 14 sold items, rating 1/5 from 11 reviews, last seen 2026-06-04.
That is enough for a reseller to decide whether to click.
๐ธ Run 2: exact listing price tracking
For PRICE_TRACK, I used two real item URLs from the search run:
{
"mode": "PRICE_TRACK",
"itemUrls": [
"https://www.vinted.fr/items/9089776821-nike-air-force-1-shadow-unisex-numero-45",
"https://www.vinted.fr/items/9089774198-nike-air-pegasus-volt-green-neon-eur42-hq5403-700"
],
"trackingStoreName": "devto-series-price-track-2026-06-04",
"maxConcurrency": 1,
"requestDelayMs": 500
}
Live result:
| Field | Value |
|---|---|
| Run ID | nWdbpqX2JKdZLs1ad |
| Dataset ID | TkFl0ztR6QMXa65MM |
| Status | SUCCEEDED |
| Duration | 359s |
| Rows emitted | 2 |
| Free-tier estimated charge | $0.024 |
This run was slow because Vinted returned several 403s.
That is the interesting part.
From the run log:
Browser price fallback failed for item 9089776821: timed out after 30000ms
Price unavailable for item 9089776821; history not updated
Resolved item 9089774198 price through browser fallback
Price tracked for item 9089774198: 39.99 EUR (0% drop)
This is exactly the kind of boring log I want in a scraper.
Not because timeouts are good.
Because the Actor did not corrupt the price history when extraction failed.
๐ก๏ธ The important fallback
For the first item, price extraction failed.
The Actor returned:
{
"itemId": 9089776821,
"currentPrice": null,
"currency": "EUR",
"priceHistory": [],
"priceDropPct": 0,
"priceUnavailable": true,
"warning": "Current price could not be extracted; price history was not updated."
}
That is the right failure mode.
| Failure | Bad behavior | Safer behavior |
|---|---|---|
| Price blocked once | โ Write 0 into history |
โ
Mark priceUnavailable
|
| Browser fallback times out | โ Delete previous history | โ Keep history clean |
| API returns 403 | โ Crash whole watchlist | โ Continue to next item |
For the second item, the browser fallback worked:
{
"itemId": 9089774198,
"currentPrice": 39.99,
"currency": "EUR",
"priceHistory": [
{
"price": 39.99,
"date": "2026-06-04T20:27:02.852Z"
}
],
"priceDropPct": 0
}
The log confirmed it:
Resolved item 9089774198 price through browser fallback
Price tracked for item 9089774198: 39.99 EUR (0% drop)
๐ Two rows, two different meanings
Both rows came from the same run, but they should trigger different actions:
| Item | Result | Action |
|---|---|---|
9089776821 |
priceUnavailable: true |
Keep previous history, retry later |
9089774198 |
currentPrice: 39.99 |
Store history point, compute future drops |
This distinction is important for alerts.
If a scraper treats "blocked once" as "price is zero", every downstream alert becomes garbage.
For a real watchlist, I want this rule:
No extracted price = no price-history mutation
That is less exciting than a fake discount alert, but it is much safer.
๐งพ Persistent price tracking contract
The trackingStoreName is the anchor:
{
"trackingStoreName": "devto-series-price-track-2026-06-04"
}
Use one stable store name per watchlist.
| Store naming style | Good? | Why |
|---|---|---|
daily-af1-watchlist-fr |
โ | Stable and specific |
seller-adwatches-watchlist |
โ | Seller-scoped |
test |
โ | Easy to reuse by accident |
price-track |
โ | Too broad |
| New random name every run | โ | No persistent history |
The store name is what turns a run into a history.
Without it, you are just re-scraping the current price.
๐ Webhook shape
For scheduled alerts, I would not send the full dataset every time.
I would send a compact payload like:
{
"workflow": "vinted-price-watchlist",
"itemId": 9089774198,
"currentPrice": 39.99,
"priceDropPct": 0,
"priceUnavailable": false,
"runId": "nWdbpqX2JKdZLs1ad"
}
Or for unavailable prices:
{
"workflow": "vinted-price-watchlist",
"itemId": 9089776821,
"priceUnavailable": true,
"action": "do_not_update_history"
}
For Telegram, I would keep it even shorter:
Vinted price watch: 9089774198 still at 39.99 EUR. No drop yet.
And for a failed extraction:
Vinted price watch: 9089776821 price unavailable. History not changed.
The second message is not glamorous, but it prevents bad decisions.
๐ธ Cost and scheduling guardrails
The live PRICE_TRACK run emitted 2 rows.
At the Free pricing available when I ran it:
$0.020 / Actor start
$0.002 / result row
The estimated charge was:
$0.020 + (2 * $0.002) = $0.024
The bigger risk is time, not just row cost.
This run took 359s because of fallback behavior.
So I would not schedule a huge exact-URL watchlist every few minutes.
| Watchlist size | Cadence I would start with | Why |
|---|---|---|
| 1-5 exact URLs | Every few hours | Acceptable if items are high-value |
| 5-20 exact URLs | Daily | Better balance |
| 20-100 URLs | Daily/weekly split | Avoid one slow run blocking everything |
| Broad discovery | Use SELL_THROUGH_TRACKER instead |
Exact URLs are the wrong tool |
โ Alert rules I would trust
For price tracking:
| Condition | Alert? |
|---|---|
priceDropPct > 10 |
โ |
priceUnavailable: true once |
โ |
priceUnavailable: true multiple times |
Maybe, as a health warning |
| New price history point, no drop | โ |
| Exact watched item disappears | Use sell-through/missing logic |
For seller watchlists:
| Condition | Alert? |
|---|---|
| Active item count jumps | โ |
| Seller appears in a profitable query repeatedly | โ |
| Rating count changes | Maybe |
| Last seen changes | Usually no |
The goal is not more alerts.
The goal is fewer, better alerts.
โ What I would schedule
| Workflow | Schedule | Why |
|---|---|---|
| Seller profile | Daily | Slow enough, useful for seller watchlists |
| Price track 5-20 exact URLs | Daily | Good for item-specific monitoring |
| Sell-through query | Daily or every few hours | Best market movement signal |
| Sold explicit pages | Only when needed | Can return zero by design |
๐ Try it
Run the Actor here:
https://apify.com/kazkn/vinted-smart-scraper?fpr=8fp2od
For price tracking, the rule is:
one watchlist = one stable trackingStoreName
Do not reuse the same store for unrelated item groups unless you intentionally want those histories together.
Top comments (0)