eMAG Products & Price Scraper (RO / BG / HU) avatar

eMAG Products & Price Scraper (RO / BG / HU)

Pricing

from $1.05 / 1,000 results

Go to Apify Store
eMAG Products & Price Scraper (RO / BG / HU)

eMAG Products & Price Scraper (RO / BG / HU)

Scrape product listings from eMAG, the largest online marketplace in Romania, Bulgaria and Hungary. Every row carries both prices, the discount, rating, review count, the full category trail, Genius status and all three product IDs. Search by keyword or walk an exact category URL.

Pricing

from $1.05 / 1,000 results

Rating

0.0

(0)

Developer

Ibnu Adzim

Ibnu Adzim

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Scrape product listings from eMAG — the largest online marketplace in Romania, Bulgaria and Hungary.

What you get

One row per product (recordType: PRODUCT):

productId · offerId · pnk · productName · productUrl · priceValue · oldPriceValue · discountPercent · currency · ratingAverage · reviewCount · categoryName · categoryTrail · departmentId · availabilityCode · isGenius · hasUnfairPrice · listingPosition · pageNumber · searchRank

Plus a SEARCH_SUMMARY per listing and an ERROR row per failed input, so every input maps to at least one row.

Two ways to point at a listing

{ "searchQueries": ["laptop", "casti bluetooth"], "country": "RO" }
{ "categoryUrls": ["https://www.emag.ro/laptopuri/c"], "country": "RO" }

Both produce identical PRODUCT rows. Use categoryUrls when you need exactness — and read the next section for why that matters.

The two search traps — read these

1. A keyword search can redirect into a curated category. /search/laptop 302s to /laptopuri/c. The rows then describe that category, not your keyword, and the count differs. Not an error, but you should know: every summary row carries redirectedToCategory and finalUrl.

2. A keyword eMAG cannot match still returns 60 confident products. There is no "no results" page. eMAG fuzzy-matches into some department:

QueryeMAG's own headline
zzqqxxnonsense12345193 de rezultate in Piese auto pentru "zzqqxxnonsense12345"
qwertyuiopasdfgh999200 de rezultate in Piese auto pentru "qwertyuiopasdfgh999"

Zero overlapping product IDs between those two — so it is not one fixed fallback set, it is genuinely different junk each time, with a confident count attached. Six "no results" phrasings were searched for in the HTML; none exists.

There is no gate that can be trusted, so this actor guesses nothing. It emits eMAG's own headline verbatim as upstreamResultsText, with the department parsed out as matchedDepartment, and logs it. If your electronics query landed in car parts, you will see it. categoryUrls is the exact alternative.

Rate limiting — the thing that will actually bite you

eMAG answers a client that has burst with HTTP 511 and a 3 KB body, and the block persists for minutes on that exit IP.

It looks like a TLS allowlist at first: an initial ladder had 8 of 9 profiles on 511 with only safari18_0 at 200. Re-testing the same profile over time disproved that —

t+0s chrome124 → 200 (1.22 MB)
t+15s chrome124 → 200 (1.22 MB)
t+60s chrome124 → 511
t+135s chrome124 → 511

— the ladder had simply been run after a burst. So:

  • the defaults here are deliberately slow: 2 concurrent, 1.5 s between request starts
  • recovery rotates the exit IP, not just the fingerprint — the throttle keys on IP
  • Residential proxy is the default, and what matters is pool size, not stealth: a datacenter range exhausts into the same block
  • a run that still cannot get through emits a rate_limited ERROR row saying exactly that, rather than an empty dataset

Known limits

  • No detail-page pass. The listing card already carries name, both prices, rating, review count, the full category trail and all three ID systems — and the detail page sits behind the same per-IP throttle. A detail pass would multiply requests against the one resource this target meters, to re-fetch most of what you already have.
  • availabilityCode is passed through raw (1/2/3). eMAG does not document the mapping publicly and it was not verifiable by observation, so no invented labels.
  • Seller name is not on the listing card. Only the Genius badge and the offer ID are.

Extraction

No JSON blob carries the listing. The single application/ld+json block on a listing page is an FAQPage, not products, and div.card-v2 is an empty shimmer placeholder — reading it returns 78 blank cards. The real data is in data-* attributes on div.card-item.card-standard (60 per page, server-rendered, complete).

Pagination is honest: pages 1/2/3/10 share zero product IDs, and past the end pages shrink then empty rather than re-serving page 1 (p50 → 60 cards, p100 → 18, p200 → 0, against a category reporting 5,958 products). The whole catalogue is reachable.

Policy

emag.ro/robots.txt names no AI crawler, and /search/ and the /<category>/c listing paths are allowed for User-agent: *. Only public product listings are read — no login, no user data, no personal profiles.