Salla Store Catalog & Price Scraper
Pricing
from $2.50 / 1,000 results
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
Maintained by CommunityActor stats
0
Bookmarked
9
Total users
3
Monthly active users
13 days ago
Last modified
Categories
Share
Enter a Salla store link to get its public products, prices and stock as rows you can download in CSV, Excel or JSON. No store API key is needed.
Use onlyChanges for repeat monitoring: after the first run, receive only new
products and changes to prices or availability.
Try five products first
The input form starts with one store and a five-product limit. Click Start, then open Output to see the rows. The same small example in JSON is:
{"stores": ["salla.sa/coffee_souq"],"maxProductsPerStore": 5,"onlyChanges": false,"respectRobots": true}
The example reads a live third-party catalog, so product names, prices and
availability can change. If that store becomes unavailable, replace its link
with another public Salla store. RUN_REPORT lists unresolved stores and
whether a catalog read stopped early.
Monitor a store every day
Save a Task with the input below, then use Apify's Schedules to run that
same Task daily. Keep stateStoreName unchanged between runs; give each
separate monitor its own name.
{"stores": ["salla.sa/coffee_souq"],"maxProductsPerStore": 1000,"onlyChanges": true,"stateStoreName": "salla-coffee-daily","respectRobots": true}
The first run establishes a baseline and returns NEW rows. A repeat run with
no watched changes correctly returns zero rows. A changed product returns
UPDATED, previousPrice and changedFields. Check RUN_REPORT to distinguish
a quiet store from an unresolved store or an incomplete read. The limit here
covers at most 1,000 products checked; raise it if you need a larger catalog.
See the daily price and stock monitoring guide for the full workflow and how to interpret a repeat run.
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_souqcoffee_souqotor200sa.comwww.otor200sa.comhttps://otor200sa.com/ar/xvXnyXKcoffeesouq1.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.
These two rows are from real run UNnqswydfejTDG2nh, build 0.1.9,
checked on 7 October 2026 at 02:09 Kuwait time (6 October, 23:09 UTC).
The five-product quick start succeeded with five distinct product IDs. This
is a sample of the catalog, not a complete store scan; prices can change.
productId | name | price | regularPrice | currency | isOutOfStock |
|---|---|---|---|---|---|
1589226865 | قهوة صوت تروبيكال كواومبيا انفيوجن 125 جرام | 60 | 60 | SAR | false |
1301644920 | ماتشا كاجورا درجة ممتازة بيور | 30 | 33.04 | SAR | false |
Plus sku, gtin, mpn, salePrice, isOnSale, discountPct, discountStarts,
discountEnds, isAvailable, quantity, unlimitedQuantity, brand,
category, productType, status, tags, rating, ratingCount, 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 bydiscountPct - Stock-out alerts —
onlyChangesreturns a product whenisOutOfStockflips - 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 successful read updates the saved state for the products it checked. A read
capped by maxProductsPerStore merges that sample into the prior state and
keeps unseen products unchanged; it does not prove the whole store is unchanged.
If a request fails partway, or the run stops at your spending limit while
reading the catalog, the old state is kept and those products are compared
again on the next run. A product delivered just before that stop can therefore
be delivered again. Removed-product detection still requires the complete
catalog read described above.
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 secondscoffee_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.
Overlapping pages do not create duplicate rows. Within each store read,
a product id (or its URL if there is no id) is delivered at most once. The
report's duplicateProducts counts repeated records skipped. A repeated
pagination cursor or an API error payload stops the read as incomplete, keeps
the previous monitor state and never counts unseen products as removals.
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.