DEV Community

Cover image for Seller Watchlists, Price Drops, and Webhooks: The Vinted Signals I Actually Schedule
KazKN
KazKN

Posted on

Seller Watchlists, Price Drops, and Webhooks: The Vinted Signals I Actually Schedule

After testing sell-through and country comparison, I wanted to check two smaller signals:

  1. Seller profiles.
  2. 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
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ” 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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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."
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

The log confirmed it:

Resolved item 9089774198 price through browser fallback
Price tracked for item 9089774198: 39.99 EUR (0% drop)
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“Š 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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

Or for unavailable prices:

{
  "workflow": "vinted-price-watchlist",
  "itemId": 9089776821,
  "priceUnavailable": true,
  "action": "do_not_update_history"
}
Enter fullscreen mode Exit fullscreen mode

For Telegram, I would keep it even shorter:

Vinted price watch: 9089774198 still at 39.99 EUR. No drop yet.
Enter fullscreen mode Exit fullscreen mode

And for a failed extraction:

Vinted price watch: 9089776821 price unavailable. History not changed.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The estimated charge was:

$0.020 + (2 * $0.002) = $0.024
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Do not reuse the same store for unrelated item groups unless you intentionally want those histories together.

Top comments (0)