# MercadoLibre Reviews Scraper (`stilled_stalagmite/mercadolibre-reviews-scraper`) Actor

Scrape aggregate product ratings from MercadoLibre: average score, rating breakdowns, and review counts.

- **URL**: https://apify.com/stilled_stalagmite/mercadolibre-reviews-scraper.md
- **Developed by:** [Danilo Frias](https://apify.com/stilled_stalagmite) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## MercadoLibre Reviews Scraper

Scrapes public product review data from MercadoLibre Mexico (`mercadolibre.com.mx`)
without any login. Useful for market researchers, e-commerce analysts, and
competitive-intelligence teams who need per-product review signals from
MercadoLibre Mexico while staying strictly on public, logged-out pages.

### What it actually scrapes (read this first)

Individual product reviews (review title, review text, review date) on
MercadoLibre Mexico are **gated for logged-out visitors**: product detail pages
redirect to an account-verification page, and the public API returns 403 for
anonymous requests (evidence below). This actor therefore scrapes the closest
reachable public surface: the public deals page
(`https://www.mercadolibre.com.mx/ofertas`), which embeds a per-product
aggregate review rating ("Calificacion 4.8 de 5 estrellas") in its page data.

Each output record carries the product's title, URL, and aggregate `rating`
(rounded to an integer on a 1-5 scale). The `review_title`, `review_text`, and
`review_date` fields are present in the schema but are always `null`, because
the individual review records they would hold are not publicly reachable.

### Inputs

| Field | Type | Default | Description |
|---|---|---|---|
| `start_urls` | array of strings | `["https://www.mercadolibre.com.mx/ofertas"]` | Public MercadoLibre Mexico listing pages to scrape for per-product review ratings. The default is the public deals page, the only surface verified reachable without login. |
| `max_items` | integer | `48` | Maximum number of product records pushed to the dataset. The default deals page carries ~48 product cards. |
| `country` | string | `"mx"` | MercadoLibre country site. Only `"mx"` (mercadolibre.com.mx) was verified against the public review surfaces; other values log a warning. |

### Sample output record

```json
{
  "product_title": "Soldadora Inversora Portatil Mma+tig Maquina 2en1 Color Amarillo",
  "product_url": "https://www.mercadolibre.com.mx/soldadora-inversora-portatil-mmatig-maquina-2en1-color-amarillo/p/MLM63723900",
  "rating": 5,
  "review_title": null,
  "review_text": null,
  "review_date": null
}
```

`rating` is parsed from the page's "Calificacion 4.8 de 5 estrellas" text and
rounded to an integer (4.8 -> 5). Products whose card has no rating component
get `rating: null`.

### Coverage and limits

- \~48 records per run from the default deals page (one page, `limit: 48`).
- Only aggregate ratings are available publicly; individual review text, titles,
  and dates are gated (see evidence below).
- Plain HTTPS with a normal browser User-Agent, ~1 request/second between
  pages, no proxies, no JavaScript rendering.
- Page structure changes on MercadoLibre's side can break the embedded-JSON
  parsing; the actor logs a warning and returns zero rows for that page rather
  than failing the run.

### Evidence that individual reviews are gated (verified 2026-09-25)

- `https://www.mercadolibre.com.mx/<slug>/p/MLM63723900` (real product detail
  page): HTTP 302 -> `https://www.mercadolibre.com.mx/gz/account-verification?go=...`
- `https://listado.mercadolibre.com.mx/celular-smartphone`: HTTP 302 ->
  `https://www.mercadolibre.com.mx/gz/account-verification?go=...`
- `https://api.mercadolibre.com/items/MLM1040520105`: HTTP 403
  (`PA_UNAUTHORIZED_RESULT_FROM_POLICIES`) for anonymous requests; the same for
  `/sites/MLM/search`. MercadoLibre retired anonymous access to these endpoints.
- `https://www.mercadolibre.com.mx/noindex/catalog/reviews/MLM63723900`: HTTP 200
  and not redirected, but the review list renders client-side only; a plain
  fetch shows "Este producto aun no tiene comentarios" / "Algo salio mal" and
  the underlying XHR endpoint is not discoverable from the public shell.
- `https://www.mercadolibre.com.mx/ofertas`: HTTP 200, no redirect, embeds
  per-product rating data. This is the surface the actor uses.

### Data rules

- **Public pages only.** No login flows, no session cookies, no CAPTCHA
  solving, no proxy services.
- **No personal data.** Reviewer identities are never collected: there is no
  reviewer name, username, email, or identifier field in the output, and none
  is extracted at any stage.

### Local test

```bash
cd mercadolibre-reviews-scraper
mkdir -p storage/key_value_stores/default
echo '{"start_urls":["https://www.mercadolibre.com.mx/ofertas"],"max_items":48,"country":"mx"}' \
  > storage/key_value_stores/default/INPUT.json
/path/to/venv/bin/python main.py
```

# Actor input Schema

## `country` (type: `string`):

MercadoLibre country site. Only 'mx' (mercadolibre.com.mx) was verified against the public review surfaces.

## `max_items` (type: `integer`):

Maximum number of product records to push to the dataset.

## `start_urls` (type: `array`):

Public MercadoLibre Mexico listing pages to scrape for per-product review ratings. Defaults to the public deals page, the only surface verified reachable without login.

## Actor input object example

```json
{
  "country": "mx",
  "max_items": 48,
  "start_urls": [
    {
      "url": "https://www.mercadolibre.com.mx/ofertas"
    }
  ]
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("stilled_stalagmite/mercadolibre-reviews-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("stilled_stalagmite/mercadolibre-reviews-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call stilled_stalagmite/mercadolibre-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stilled_stalagmite/mercadolibre-reviews-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oaLkCwPqrArJR6qsn/builds/ND9DV50kf6pfkusU1/openapi.json
