Salla Store Catalog & Price Scraper avatar

Salla Store Catalog & Price Scraper

Pricing

from $2.50 / 1,000 results

Go to Apify Store
Salla Store Catalog & Price Scraper

Salla Store Catalog & Price Scraper

Products, prices and stock from any Salla store. Give it a normal store link - it works out the API identifier itself. HTTP only, no browser, no key.

Pricing

from $2.50 / 1,000 results

Rating

0.0

(0)

Developer

ABDULWAHAB NASER RASHED ALQARAWI

ABDULWAHAB NASER RASHED ALQARAWI

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

3

Monthly active users

3 days ago

Last modified

Share

Products, prices and stock from any Salla store — Saudi Arabia's largest e-commerce platform.

Give it a normal store link. No API key, no browser, no proxy.


The identifier problem, solved

Salla's API needs a Store-Identifier header that no shop owner has ever seen. An Actor that asks you for it is asking for something you do not have.

This one works it out itself — and when a link's name is not the store's name, it reads the store's real identity from its own page. All of these work:

salla.sa/coffee_souq
coffee_souq
otor200sa.com
www.otor200sa.com
https://otor200sa.com/ar/xvXnyXK
coffeesouq1.com (a custom domain whose name differs from the store's)

What you get

One row per product, 35 fields, every one always present — missing values come back as null, never dropped.

FieldExample
nameمجموعة أورموند جين فيستيف كاليندر
price1150.0
regularPrice1955.0
currencySAR
isOnSaletrue
discountPct41.18
isOutOfStocktrue
categoryللجنسين
rating / ratingCount4.5 / 2

Plus productId, sku, gtin, mpn, salePrice, discountStarts, discountEnds, isAvailable, quantity, unlimitedQuantity, brand, productType, status, tags, weight, imageUrl, hasOptions, productUrl, store, scrapedAt, and changeType / previousPrice / changedFields / previousValues / discountEnded (filled only with onlyChanges, see below).

A real discount, not a claimed one. Some stores set the on-sale flag with both prices equal; discountPct is filled only when the regular price is genuinely higher, and onlyOnSale returns only those products.

Stars with their count. rating alone would make five stars from two buyers look like five stars from five hundred; ratingCount says which.


Use it for

  • Competitor price monitoring — schedule it with onlyChanges
  • Discount tracking — set onlyOnSale, sort by discountPct
  • Stock-out alerts — onlyChanges returns a product when isOutOfStock flips
  • Catalog and market research across Saudi and Gulf stores

Only what changed

Turn on onlyChanges and schedule the Actor. Each run returns only products that are new, or whose price, regularPrice, isAvailable or isOutOfStock changed since the last run. Every row says why: changeType is NEW or UPDATED, and previousPrice holds the price it had before (null for new products). The first run returns every product as NEW. An UPDATED row also lists the watched fields that moved in changedFields (for example ["price"]) and all four watched values from before in previousValues; both are null on NEW rows.

Removed products (emitRemoved, off by default). With onlyChanges on, also returns a REMOVED row — product id, URL, name and SKU as last seen, and previousValues — for each known product that is no longer in the store. A removal row is a delivered row and is charged like any other. Removals are reported only after a read that is genuinely complete: the cursor walked to its end, no request failed, no product skipped or missing an id, not stopped by maxProductsPerStore, the page guard or the spending limit, and onlyOnSale off. Any other run reports no removals and says why in the run report (removalNote). A product is forgotten only once its removal row was delivered; if the spending limit stops the run first, the rest are reported next run. A state saved by a build before this option existed is first re-recorded by one complete read, so turning emitRemoved on never reports removals on its first run.

Ended discounts (includeEndedDiscounts, off by default). With both onlyOnSale and onlyChanges on, a product whose discount ended is normally filtered out, because it is no longer discounted. Turn this on to receive it as an UPDATED row with discountEnded: true. Only a discount this build recorded counts: a snapshot saved by an older build did not record discounts, so an ending in the first run after upgrading is not recognised.

The last known state of each store is kept in a named key-value store in your account (stateStoreName, default salla-catalog-state). Use a different name for each separate monitor.

A store's state is saved only when its read finished cleanly. If a request fails partway, or the run stops at your spending limit, the old state is kept and those products are compared again on the next run — a change is never skipped, though a product delivered just before the stop can be delivered again.

With onlyChanges on, maxProductsPerStore caps the products checked, not the rows returned; otherwise a store with nothing new would be read to its last page on every run.


Speed

Measured 14 Sep 2026 on a local machine, default 200 ms delay between pages:

otor200sa 300 products 21 requests 15.6 seconds
coffee_souq 300 products 21 requests 17.7 seconds

That is 0.75–0.85 s per page of 15, delay included, so a 1,000-product store takes roughly a minute. Speed on Apify's servers will differ.


Honest notes

Pagination is cursor-only. page= is ignored and per_page is capped at 15 by the API — not by this Actor. The cursor is walked for you.

A store is confirmed only when products come back. The API answers "success" with zero products for a wrong identifier, so a success code alone is never trusted. A store that cannot be confirmed is listed in the run report under unresolved, and named in the run's status message.

One odd product never fails the run. A product whose data arrives in an unexpected shape is skipped, counted under skippedProducts in the run report, and every other product is delivered.

No personal data. The payload's availability_notify block holds booleans about notification channels, not anyone's contact details. Nothing identifying a person is collected.

robots.txt is honoured on both sites it reads. api.salla.dev's file is read before any product request; it allows a normal agent on this path and disallows a named list of AI crawlers, and this Actor ships its own identifier. When a link's name is not the store's identifier, the store's own page is read to find it — and that site's robots.txt is checked first. If it disallows the page, the page is not read and the store is listed as unresolved.

maxProductsPerStore counts rows returned. Products filtered out by onlyOnSale do not use it up (see onlyChanges above for the one exception).

Arabic links do not break the run. An Arabic domain is looked up in its DNS form; an Arabic slug cannot be a Salla API identifier, so the store's page is read instead.

Every run publishes a report to the key-value store under RUN_REPORT: requests, rows, unresolved stores, skipped products, cost per 1,000 rows, and for each store the identifier it resolved to, whether its read was cut short (truncated), and a catalog summary of the products read — count, real discounts, out of stock, and minimum, median and maximum price.


Questions, or a store that will not resolve?

Open an issue with the store link. Most failures are one store's theme, and they are usually quick to fix.