OLX Brazil Scraper API avatar

OLX Brazil Scraper API

Pricing

Pay per event

Go to Apify Store
OLX Brazil Scraper API

OLX Brazil Scraper API

Read olx.com.br search and category pages and get one row per listing: id, title, price in BRL, category, city and state, publish date, image URLs, per-category attributes and whether the seller is private or a business. $0.85 per 1,000 listings.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

2 days ago

Last modified

Share

Reads search and category result pages on olx.com.br and gives you one row per listing: id, title, price in BRL, category, city and state, publish date, image URLs, whether the seller is private or a business, and the listing URL.

It runs without a browser and never fetches a per-listing detail page, because it doesn't need to. About 50 listings come back per request. Seller phone numbers are not included, and the section below explains why.

What it returns

One row per listing. The percentages are real coverage measured on the shipped build over a 300-row run on ?q=iphone and a 120-row run on imoveis/venda/estado-rj, both on 2026-08-10:

FieldFilledExample
listingId100%1517568906
title100%iPhone 12 Pro Max 128GB | Conservado | Caixa Original
price / priceLabel100%3000 / R$ 3.000
currency100%BRL
oldPrice / oldPriceLabel19%3200 / R$ 3.200, only when the seller cut the price
category / categoryId / parentCategoryId100%Celulares e Smartphones / 3060 / 3000
city / state / stateName100%São Paulo / SP / São Paulo
neighbourhood95–98%Paraíso do Morumbi
areaCode / locationLabel100%11 / São Paulo, Paraíso do Morumbi - DDD 11
publishedAt / publishedTimestamp100%2026-08-10T01:54:40.000Z / 1786413280
sellerType100%private or business
sellerName100%Fatima — the public display name on the ad
thumbnailUrl / imageUrls / imageCount100%first image, all images, count
hasVideoalways presenttrue on 0% of both runs
isFeaturedalways presenttrue on 25% (phones), 1% (property)
isBumpedalways presenttrue on 1% (phones), 0% (property)
hasFreeShippingalways presenttrue on 100% (phones), 0% (property)
attributes100%{ "Marca": "APPLE", "Modelo": "IPHONE 12 PRO MAX", "Condição": "Usado" }
url100%the listing page
searchUrl, page, position, scrapedAt100%provenance
searchQueryonly when you passed a search termiphone

Attribute keys come straight from OLX and differ per category. On the phone run every row carried Categoria, Condição, Cor, Marca, Modelo, plus Memória interna and Saúde da bateria on 98%. On the property run every row carried Categoria, Tipo, Quartos, Banheiros, plus Condomínio on 99% and IPTU on 95%.

What it does not do

  • No seller phone numbers. They are not in the payload this actor reads, and it does not go looking for them anywhere else. sellerType and the public display name are all you get.
  • No single-listing pages. Paste a search or category URL, not an ad URL. An ad URL returns an uncharged diagnostic row explaining that.
  • No jobs. vagas-de-emprego is a separate OLX product that renders through a different component and carries no listing payload on the results page.
  • No more than about 5,000 listings per search. OLX serves 50 per page and repeats page 100 forever after that — ?o=101 and ?o=150 return byte-for-byte the same 50 ads as ?o=100. Narrow by state, category or price band to reach deeper stock.
  • No "highest price first" sort. OLX offers it in its own UI but does not expose it as a URL parameter that survives a plain request. Relevance, newest and lowest-price all work.

Input

{
"searchQueries": ["notebook"],
"category": "informatica",
"state": "SP",
"sortBy": "date",
"minPrice": 500,
"maxPrice": 3000,
"maxItems": 250
}

Or paste URLs and keep every filter you already set in the OLX UI:

{
"startUrls": ["https://www.olx.com.br/celulares/estado-sp?q=iphone&ps=1000&pe=3000"],
"maxItems": 100
}

Every input above was checked against live result counts before it was exposed: state cut an iphone search from 103,531 to 19,372 listings, the ps/pe price band cut it to 46,186, category + state and both sort orders all changed the returned set.

region narrows inside a state using the slug OLX shows in its own URLs, for example sao-paulo-e-regiao. A region slug OLX does not recognise is ignored silently. You get the whole state back with no error at all. This actor detects that and adds one uncharged REGION_NOT_APPLIED row listing the region slugs that would have worked.

Empty input returns one labelled sample row and charges nothing.

How it works, and why it used to fail

OLX is a Next.js App Router site with no public JSON search endpoint. The listing data is in the React Server Component payload, as a plain "ads": [ ... ] array with every listing already denormalised — no detail-page fetch is needed for any field listed above.

The hard part was reaching it. olx.com.br is behind a Cloudflare firewall rule that refuses most datacenter addresses with a 5.8 KB "Sorry, you have been blocked" page, which is why earlier versions of this actor succeeded or failed apparently at random.

That rule only matches requests shaped like a top-level page navigation. Measured across 14 fresh Apify datacenter exit addresses, same minute, same TLS fingerprint:

Request shapeAddresses served
plain page request1 / 14
+ x-requested-with: XMLHttpRequest8 / 14
+ RSC: 1 and a same-origin referer8 / 14

The actor sends both headers and takes the RSC form, whose response is the flight payload alone. That's 260 KB instead of 730 KB, and about twice as fast. For the addresses still refused, it walks a ladder of exit addresses until one is served and then pins it for the rest of the run; a pinned address returned 25 pages out of 25 without a single refusal. Requests use impit with Chrome's real TLS fingerprint, because plain Node is rejected at the handshake.

Measured on the Apify platform, 2026-08-10: 32 of 32 runs succeeded, including 10 deliberately run with the container's own address disabled, so that every request had to go through the exit ladder. Those 10 needed at most 3 addresses each. A 999-listing run took 58 seconds.

Billing

$0.85 per 1,000 listings, plus a $0.001 start fee per run. It's a flat rate, the same number on the free plan as on any paid one.

Blocked requests, empty results, bad URLs, the region warning and the sample row are never charged. You pay for listings actually returned, one charge per row.

FAQ

Can I scrape OLX Brazil without a Brazilian IP address? Yes. This actor runs from ordinary US datacenters and never uses a Brazilian address. OLX's firewall rule is about address reputation and request shape, not geography.

Why did my run return zero rows and a BLOCKED row? Every exit address the run had available was refused. That's rare now, 0 of 32 test runs hit it, but if it happens, re-run, or put your own proxy URLs in proxyConfiguration. Nothing was charged.

How many listings can I get for one search term? About 5,000: 50 per page, 100 pages, then OLX repeats page 100. Split by state, category or price band to go deeper. A 1,000-listing run took 58 seconds.

Does it return the seller's phone number? No, by design.

Can I monitor new listings? Set sortBy to date and a small maxItems. Newest ads come first and every row carries publishedAt, so you can diff against your last run.

What currency are prices in? Brazilian reais. price is numeric, priceLabel keeps OLX's own formatting.

Does it work for property and cars, not just goods? Yes. imoveis/venda, imoveis/aluguel and autos-e-pecas/carros-vans-e-utilitarios are all result pages with the same payload; a property run returns Quartos, Banheiros, Condomínio and IPTU in attributes.