# Elektra Mexico Product & Price Scraper (`superslowsloth/elektra-products`) Actor

Elektra Mexico price and stock scraper: search elektra.mx by keyword and get one row per SKU with price and list price in MXN, discount, stock, seller, EAN, brand, category, interest-free instalments and URL. Sort by price, sales, discount or newest. For daily price monitoring.

- **URL**: https://apify.com/superslowsloth/elektra-products.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.28 / 1,000 product scrapeds

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

## Elektra Mexico Product & Price Scraper

Search [Elektra](https://www.elektra.mx) (Mexico's large electronics, furniture
and appliance retailer, on the VTEX commerce platform) for one or more keywords
and get one flat row per **SKU**: the selling price and the list price in
**MXN**, the discount percent, whether it is in stock and how many, the seller,
EAN barcode, brand, category, the most interest-free instalments (meses sin
intereses), image and the product URL. Run it on a schedule and diff the dataset
to get an **Elektra price and stock watch**: track what a laptop, a fridge or a
phone costs today against last week, and which SKUs went out of stock.

No account, no API key, no login, no browser. One request returns 50 products.

### Input

| Field | Notes |
|---|---|
| `searchTerms` | One or more search terms, one per line. Required. Spanish and brand names work (`laptop`, `refrigerador samsung`, `iphone 16`). A SKU found by two terms is returned once, under the first. Elektra matches loosely: `laptop` finds about 1,400 products, many of them backpacks and stands. |
| `maxItems` | Rows to read per search term (default 100, up to 10,000). A row is a SKU, so a product with six colours is six rows. |
| `sort` | `relevance` (default), `best-selling`, `price-asc`, `price-desc`, `newest`, `biggest-discount`. |
| `inStockOnly` | Skip SKUs Elektra reports as unavailable (not returned, not charged). Off by default. |
| `proxyConfiguration` | Apify datacenter proxy by default. |

#### About the sorts

Each sort was checked against the live catalogue (2026-10-15).

- `price-asc` and `price-desc` are **checked on every page**: the prices must run
  mostly in order, and the actor fails the term (at no charge) rather than
  return rows in an order that was not asked for. The check is deliberately
  loose, because Elektra's own price sort has the odd out-of-place row (1 in
  1,423 rows ascending, 4 descending for `laptop`): the sort key is the indexed
  price and the displayed offer is live.
- `newest` follows the product's release date and `biggest-discount` follows the
  discount percent; both were confirmed to be in order on 150 rows of `laptop`.
- `best-selling` is Elektra's `OrderByTopSaleDESC`. It differs from the default
  order; the response carries nothing to check it against.
- Elektra also has a score sort, but it returns exactly the same rows in the
  same order as best selling (identical on four terms), so it is not offered.

### Output

Prices are numbers in Mexican pesos; `currency` is always `MXN`.

| Field | Notes |
|---|---|
| `query`, `position` | The search term that first found the SKU, and where its **product** sat in Elektra's result list for that term and sort (1 is the first result). Sibling SKUs share a position. |
| `product_id`, `sku_id` | Elektra's product id and the SKU id (VTEX `itemId`). `sku_id` is unique per row in a run. |
| `name`, `sku_name`, `variant` | The product name, the SKU's full name, and the variation attributes as sent (`Capacidad: 128 GB, Carrier: Desbloqueado, Color Telefonía: Rosa`). `variant` is null when Elektra sends no variation list for the SKU, which includes some SKUs of products that do list one for their siblings. |
| `ean`, `brand` | The SKU's barcode, and the brand. Null when Elektra sends none. |
| `url`, `image_url` | The `https://www.elektra.mx/<slug>/p` product page, and the first SKU photo. |
| `category`, `category_path` | The most specific category and its breadcrumb (`["Cómputo", "Accesorios y periféricos", "Mochilas y Maletines"]`). |
| `price`, `list_price` | The selling price now, and the price before the promotion. They are equal when the SKU is not discounted. **Null when the SKU has no price** (see below). |
| `on_sale`, `discount_percent` | `on_sale` is true when `list_price` is above `price`. `discount_percent` is worked out from the two prices (one decimal place) and is **null when the SKU is not on sale**, never 0. |
| `in_stock`, `stock_quantity` | Elektra's availability flag and quantity for the chosen seller's offer. **`stock_quantity` is 99999 for stock the seller does not count** (about 1 offer in 9 in a sample of 1,064 SKUs); it is passed through as sent. |
| `seller_id`, `seller_name`, `sold_by_elektra` | The seller whose offer the row shows. Id `1` is Elektra itself; any other is a marketplace seller. |
| `max_interest_free_installments` | The most instalments offered at 0% interest (meses sin intereses). 1 means pay in full only; 24 is the most seen. Null when the offer has no instalment table. |
| `release_date` | The product's release date in Elektra's catalogue, `YYYY-MM-DD`. |

Example row (`laptop`, position 1):

```json
{
  "query": "laptop",
  "position": 1,
  "product_id": "1301907570",
  "sku_id": "1301907570",
  "name": "Kånken Laptop 13\"",
  "sku_name": "Kånken Laptop 13\"",
  "variant": null,
  "ean": "7323450785680",
  "brand": "GENERICA",
  "url": "https://www.elektra.mx/knken-laptop-13-1301907570/p",
  "image_url": "https://elektra.vteximg.com.br/arquivos/ids/33077112/61UucXzP5dL.jpeg.jpg?v=639260175163000000",
  "category": "Mochilas y Maletines",
  "category_path": ["Cómputo", "Accesorios y periféricos", "Mochilas y Maletines"],
  "currency": "MXN",
  "price": 3719.0,
  "list_price": 4091.0,
  "on_sale": true,
  "discount_percent": 9.1,
  "in_stock": true,
  "stock_quantity": 10,
  "seller_id": "711160",
  "seller_name": "ecomsellers",
  "sold_by_elektra": false,
  "max_interest_free_installments": 1,
  "release_date": "2026-09-26"
}
```

#### Why one row per SKU

VTEX nests a product over its SKUs, and the SKU is what has a barcode, a price
and a stock level. About 1 product in 4 (of 500 sampled) has several SKUs, up to
19: an "iPhone 15 Pro Reacondicionado" is ten different phones. One row per
product would show one price for all ten. Most products have one SKU and give
one row.

#### Honest nulls

A field Elektra did not send is `null`, never `0` or `""`.

- **Unpriced SKUs.** Elektra sends `Price: 0` and `ListPrice: 0` for a SKU it
  cannot currently sell, which was about 1 SKU in 4 in a sample of 1,064
  The actor reports a null
  `price`, not a price of zero pesos, and still returns the row with
  `in_stock: false`, because a stock watch needs it. Set `inStockOnly` to skip
  them.
- **Odd offers.** A few marketplace SKUs are flagged available with no price
  (`price: null`, `in_stock: true`), and a few Elektra SKUs carry a price but
  are flagged unavailable. Both are reported as sent.
- **Several sellers.** A SKU can list Elektra and a marketplace seller. The row
  shows the seller Elektra marks as the default (when none is marked, the first
  seller with a price), because the default is the one the site sells from.

### Pricing

Pay per event:

- **$0.002** per run (`actor-start`), charged only after your input is
  validated, so a run that fails on bad input costs nothing.
- **$0.00028** per row written (`product-scraped`), i.e. $0.28 per 1,000 rows. A
  row that is not written is not charged.

### How it fetches

It calls the VTEX catalog JSON behind Elektra's own search page
(`www.elektra.mx/api/catalog_system/pub/products/search?ft=<term>&_from=0&_to=49`),
50 products per request. Measured 2026-10-15: HTTP 200 or 206 and JSON from a
plain home connection with a Chrome TLS fingerprint, and a JSON product array
from an Apify datacenter exit through the in-platform probe the same day. HTTP 206 Partial Content is the normal answer for a full
page; the last page is 200. A refusal (403, 429, 202, 5xx), or a 200 that is not
the product array, is treated as the address being blocked, and the actor
rotates to a fresh one and retries. Elektra occasionally answers a good request
with a 500 (`The operation was canceled.`); that is retried the same way.

Things worth knowing, all measured:

- **Depth ceiling: 2,550 products per term.** VTEX refuses `_from` above 2,500
  (HTTP 400), so a term can be read to 51 pages of 50 however many products it
  matches (`mueble` matches 4,329). The actor stops there and **logs a warning
  when a term had more matches than that**; make the term more specific (add a
  brand, model or size) to see the rest. `maxItems` counts rows, which are SKUs,
  so a term can be exhausted before `maxItems` is reached.
- **Repeated products.** Elektra's relevance order repeats rows: a walk of
  `mueble` to the ceiling read 2,550 products of which 2,293 were distinct. The
  actor returns each SKU once and ends a term only after three pages in a row
  bring nothing new. The price sort had no repeats over 2,550 rows. To read as
  much of a big term as possible, use a price sort.
- **Page size.** VTEX serves at most 50 per page (`_to` above 50 is HTTP 400), so
  the actor never asks for more.
- **No matches.** A term with no results is a normal empty answer (`[]`), not an
  error. It is logged and the run continues with the next term. A page past the
  end of a smaller result set is also `[]`.
- **The match count moves.** `laptop` read 1,425 matches on one request and
  1,423 on the next; the count in the log is informational.
- **Heavy pages.** One page of 50 products is 1 to 2 MB of JSON, so a full
  2,550-product term moves around 80 MB.
- **Not offered.** Category and price-range filters (`fq=`) exist in VTEX but are
  not wired into this actor. An empty search term would list the whole
  660,000-product catalogue and is refused.

# Actor input Schema

## `searchTerms` (type: `array`):

What you would type into the search box on elektra.mx, one term per line (for example laptop, refrigerador samsung or iphone 16). Spanish and brand names work. Each term is searched and read separately. A SKU that two terms both find is returned once, under the first. Elektra matches loosely, so a broad word returns thousands of products; it serves at most 2,550 products per term (51 pages of 50).

## `maxItems` (type: `integer`):

Read at most this many rows (one row per SKU: a size, colour or capacity of a product) for each search term. Elektra serves 50 products per page and no more than 2,550 products per term; a term with more matches than that is logged so you can narrow it.

## `sort` (type: `string`):

The order Elektra lists the results in. 'Relevance' is its default. The two price sorts are checked against the prices on every page, and a term fails (at no charge) rather than return rows in an order that was not asked for. The other sorts are Elektra's own and cannot be checked from the prices.

## `inStockOnly` (type: `boolean`):

Skip SKUs Elektra reports as unavailable. They are read but not returned and not charged. Off by default, which returns them with a null price and in_stock false: a stock watch needs those rows, a price watch usually does not. About 1 SKU in 4 in a sample of 1,064 was unavailable.

## `proxyConfiguration` (type: `object`):

Use Apify's automatic datacenter proxy (the default). A refused request is retried from a fresh address.

## Actor input object example

```json
{
  "searchTerms": [
    "laptop"
  ],
  "maxItems": 100,
  "sort": "relevance",
  "inStockOnly": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "searchTerms": [
        "laptop"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/elektra-products").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 = {
    "searchTerms": ["laptop"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/elektra-products").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 '{
  "searchTerms": [
    "laptop"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/elektra-products --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/elektra-products"
        }
    }
}
```

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/pwxSAgPi6ofqrBsZh/builds/6dswIVi8bKThbLxLe/openapi.json
