# Shopify App Listings (`subrosa/shopify-app-listings`) Actor

Returns app listings from the Shopify App Store by category: name, developer, rating, review count, pricing summary and plans, launch date, languages and integrations.

- **URL**: https://apify.com/subrosa/shopify-app-listings.md
- **Developed by:** [Sub Rosa](https://apify.com/subrosa) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.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

## Shopify App Listings

Returns app listings from the public Shopify App Store (apps.shopify.com), by category. For each app you get the handle, name, tagline, the Partner's listed business name, the categories it is filed under, its average rating and review count, the pricing line the store shows, the pricing plan cards from the app page with each price parsed into an amount, currency and period, the launch date, whether it carries the Built for Shopify badge, the languages it is offered in, and the integrations listed under "Works with". Data is read from the store's public HTML at run time, so a run reflects the store as it is that day. Pay per event: `result` is $0.002 per item delivered ($2 per 1,000) and `actor-start` is $0.02 per run.

### Who uses it

- An app developer tracking a category: run the Actor on `marketing-and-conversion-social-trust-product-reviews` every week, keep `rating`, `reviewCount`, `pricingPlans` and `isBuiltForShopify` for every competitor, and diff the runs to see who changed a price, gained a badge, or lost ground in reviews. `pricingPlans[].amount` makes the price diff a number, not a string comparison.
- A market analyst sizing the ecosystem: run it across all leaf categories with details on, then group by `developerName`, `launchedAt` year and `pricingSummary` to measure how many apps launched per year, what share is free, and how concentrated each category is.
- A merchant or agency shortlisting tools: run one category with `includeDetails` on, filter to `isBuiltForShopify` true and `rating` above 4.5, and read `worksWith` and `languages` to find apps that fit an existing stack and storefront locale.

### Sample output

One real item from a real run:

```json
{
    "id": "judgeme",
    "appName": "Judge.me Product Reviews App",
    "url": "https://apps.shopify.com/judgeme",
    "tagline": "Collect unlimited product reviews, star ratings, testimonials",
    "developerName": "Judge.me",
    "categories": ["marketing-and-conversion-social-trust-product-reviews", "store-design-site-optimization-seo"],
    "categoryNames": ["Product reviews", "SEO"],
    "rating": 5,
    "reviewCount": 47537,
    "pricingSummary": "Free plan available. Free trial available.",
    "pricingPlans": [
        {
            "planName": "Forever Free",
            "priceText": "Free",
            "amount": 0,
            "currency": null,
            "period": null
        },
        {
            "planName": "Awesome",
            "priceText": "$15/month",
            "amount": 15,
            "currency": "USD",
            "period": "month"
        }
    ],
    "launchedAt": "2015-06-25",
    "isBuiltForShopify": true,
    "languages": [
        "English",
        "Spanish",
        "French",
        "Italian",
        "Portuguese (Brazil)",
        "German",
        "Dutch",
        "Japanese",
        "Chinese (Simplified)",
        "Chinese (Traditional)",
        "Turkish",
        "Polish",
        "Swedish",
        "Danish",
        "Romanian"
    ],
    "worksWith": [
        "Checkout",
        "Customer accounts",
        "Shopify Flow",
        "Shopify Admin",
        "AfterShip: Order Tracking",
        "Gorgias: Chat/Support",
        "Klaviyo: Email Marketing",
        "LoyaltyLion: Loyalty & Rewards",
        "PageFly Landing Page Builder",
        "PushOwl: Push Notifications"
    ],
    "sourceUrl": "https://apps.shopify.com/judgeme",
    "scrapedAt": "2026-09-26T04:36:25.335Z"
}
```

### Data dictionary

| Field                      | Type                    | Meaning                                                                                                                                                                                                                            | Example                                                                                                     |
| -------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `id`                       | string                  | The app's handle, the last path segment of its store URL. Stable for the life of the listing.                                                                                                                                      | `judgeme`                                                                                                   |
| `appName`                  | string                  | The app's listed name.                                                                                                                                                                                                             | `Judge.me Product Reviews App`                                                                              |
| `url`                      | string                  | Canonical store page for the app, without tracking parameters.                                                                                                                                                                     | `https://apps.shopify.com/judgeme`                                                                          |
| `tagline`                  | string or null          | One-line description shown under the name on listing cards and in the page title, after the house free-text filter (a filter, not a guarantee; null when nothing remains).                                                         | `Collect unlimited product reviews, star ratings, testimonials`                                             |
| `developerName`            | string or null          | The Partner's business name as the store lists it under "Developer" on the app page, taken as shown. The house does not verify whether a listed trading name embeds a person's name; see Legal. Null when `includeDetails` is off. | `Judge.me`                                                                                                  |
| `categories`               | array of string or null | Category slugs the app is filed under. With details on, all of the app's categories from its page; with details off, the one category it was found in. Slugs are the same strings the `categories` input accepts.                  | `["marketing-and-conversion-social-trust-product-reviews", "store-design-site-optimization-seo"]`           |
| `categoryNames`            | array of string or null | Display names for `categories`, in the same order.                                                                                                                                                                                 | `["Product reviews", "SEO"]`                                                                                |
| `rating`                   | number or null          | Average star rating from 1 to 5, one decimal. Null when the app has no reviews yet.                                                                                                                                                | `5`                                                                                                         |
| `reviewCount`              | integer or null         | Number of reviews behind the rating. Null when the app has no reviews yet.                                                                                                                                                         | `47537`                                                                                                     |
| `pricingSummary`           | string or null          | The pricing line exactly as the store shows it. With details on it comes from the app page and may combine two sentences; with details off it is the shorter card version.                                                         | `Free plan available. Free trial available.`                                                                |
| `pricingPlans`             | array of object or null | One entry per plan card on the app page: `planName`, `priceText`, `amount`, `currency`, `period`. Null when the page shows no plan cards, which is the case for free apps, and when details are off.                               | `[{ "planName": "Awesome", "priceText": "$15/month", "amount": 15, "currency": "USD", "period": "month" }]` |
| `pricingPlans[].planName`  | string or null          | Plan name as shown on the card.                                                                                                                                                                                                    | `Awesome`                                                                                                   |
| `pricingPlans[].priceText` | string or null          | The price exactly as the store prints it. Always present when the card has a price; this is the raw form the parsed fields come from.                                                                                              | `$15/month`                                                                                                 |
| `pricingPlans[].amount`    | number or null          | The price as a number. `0` for a card that says "Free". Null for "Free to install", for usage-based lines such as "Estimated monthly cost", for ranges, and for prices in a currency other than the US dollar.                     | `15`                                                                                                        |
| `pricingPlans[].currency`  | string or null          | `USD` when `amount` is a US dollar price. The store states on every app page that all charges are billed in USD. Null when `amount` is null and for free plans, which have no currency.                                            | `USD`                                                                                                       |
| `pricingPlans[].period`    | string or null          | The billing period named in `priceText`: `month`, `year`, or `one-time`. Null when the text names none, as for "Free" and "Free to install".                                                                                       | `month`                                                                                                     |
| `launchedAt`               | string or null          | Date the app was launched on the store, ISO 8601 date, from the "Launched" line on the app page. Null when details are off.                                                                                                        | `2015-06-25`                                                                                                |
| `isBuiltForShopify`        | boolean                 | True when the app carries the Built for Shopify badge on its card or page.                                                                                                                                                         | `true`                                                                                                      |
| `languages`                | array of string or null | Languages the app is offered in, from the "Languages" line on the app page. Null when details are off.                                                                                                                             | `["English", "Spanish"]`                                                                                    |
| `worksWith`                | array of string or null | Integrations listed under "Works with" on the app page, deduplicated (see Limits). Null when nothing is listed or details are off.                                                                                                 | `["Checkout", "Shopify Flow"]`                                                                              |
| `sourceUrl`                | string                  | Page the record was extracted from: the app page with details on, the listing page with details off.                                                                                                                               | `https://apps.shopify.com/judgeme`                                                                          |
| `scrapedAt`                | string                  | Extraction time, ISO 8601, UTC.                                                                                                                                                                                                    | `2026-09-26T04:29:02.798Z`                                                                                  |

Money follows the house convention: a number in `amount`, a sibling `currency`, and `period` for recurring prices, with the store's raw text kept in `priceText`. The parser reads exactly the forms the store prints on plan cards: "Free", "Free to install", a single US dollar amount followed by "/month", "/year" or "one-time charge". Anything else, including usage-based lines such as "Estimated monthly cost", keeps `amount` and `currency` null and the raw text in `priceText`, so you always have the source's own words to fall back on. The store also prints a line under some monthly cards ("or $290/year and save 17%"); that annual alternative is not a plan card and is not returned.

### Input

| Field                | Type            | Default                                                                                                           | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `categories`         | array of string | `["marketing-and-conversion-marketing-email-marketing", "marketing-and-conversion-social-trust-product-reviews"]` | Category slugs from `apps.shopify.com/categories/<slug>`. A full category URL is accepted and reduced to its slug. A short form such as `email-marketing` or `product-reviews` is accepted too: it is resolved against the store's category sitemap (one extra request for the run) to the full slug that ends in it; when several match, the shortest is used and the others are named in the log. Leaf categories, the ones whose page has a "View all" link, are walked page by page (24 apps a page) through the full list. Top-level and mid-level categories such as `store-design` or `marketing-and-conversion-upsell-and-bundles` have no full list on the store; for those you get the curated grid of about 40 apps the page shows. |
| `includeDetails`     | boolean         | `true`                                                                                                            | Visit each app page for `developerName`, all `categories`, `pricingPlans`, `launchedAt`, `languages` and `worksWith`. One request per app. This defaults to on, against the house habit of booleans defaulting to off, because the default run needs it on to produce the plans, launch date, languages and integrations this README promises. When off, only card fields are returned, the detail fields are null, and a run is about 24 times cheaper per item.                                                                                                                                                                                                                                                                              |
| `maxItems`           | integer         | `60`                                                                                                              | Stop after this many apps across all categories. Apps that appear in more than one requested category are delivered once. A run never delivers more than this number.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `proxyConfiguration` | object          | Apify datacenter proxy                                                                                            | Proxy settings. Datacenter proxies are enough; residential proxies are not needed. To run locally without an Apify login, set it to `{ "useApifyProxy": false }`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

The category tree has seven top-level slugs: `sales-channels`, `finding-products`, `selling-products`, `orders-and-shipping`, `store-design`, `marketing-and-conversion`, `store-management`. Each top-level page links to its mid-level and leaf categories; the leaf slugs are the ones to pass when you want a full list. Examples of leaf slugs: `marketing-and-conversion-marketing-email-marketing`, `marketing-and-conversion-social-trust-product-reviews`, `store-design-site-optimization-seo`, `finding-products-sourcing-options-dropshipping`, `orders-and-shipping-shipping-solutions-shipping`. The store's English category sitemap lists all 161 of them.

The default run (two leaf categories, details on, 60 items) makes 66 requests and finishes in a little under three minutes at the rate below.

### Pricing

Pay per event, two events. `actor-start`: $0.02, charged once at the beginning of every run, covers the fixed overhead of starting. `result`: $0.002 per item delivered, that is $2 per 1,000 items. Items are pushed and charged in the same call, so a run never delivers more items than it charges for, and the run stops cleanly when your spending limit is reached.

Measured platform cost, with details on, at 1 GB of run memory and the Free and Starter plan rates of $0.20 per compute unit and $0.20 per GB transferred: the default run makes 66 requests in about three minutes (0.05 compute units, 2.9 MB on the wire), which is about $0.01 per run. A thousand items with details on take about 1,045 requests, 44 minutes at the rate below, 0.73 compute units and 46 MB, which is about $0.16 per 1,000 items. The `result` price of $2 per 1,000 is roughly 12 times that, so retries and page growth are absorbed without a price change. With details off a thousand items take about 45 requests and cost the platform under $0.01.

The free allowance is the Apify free plan's monthly credit, $5 to spend in the store, not a free Actor. At $0.02 per start and $0.002 per result, one default run costs $0.14, so the monthly credit covers about 35 default runs of 60 items, or up to about 2,400 items in a single run.

### Limits and honesty

- Search is not supported. The store's `robots.txt` disallows every URL containing `q=`, which is how its search works, so there is no `query` input. Use categories.
- Only leaf categories have a full, paginated list on the store. A top-level or mid-level slug returns the curated grid on that page (about 40 apps), not every app in the tree below it. To cover a tree, pass its leaf slugs.
- The order of items follows the store's default sort for the category, which the store chooses (it is a relevance ranking, not alphabetical and not by rating). Do not treat position as a stable rank.
- Reviews and reviewer identities are not collected, by design. The app page carries reviews; the extractor reads only the aggregate `rating` and `reviewCount`, which the page also publishes as structured data.
- `pricingPlans` is null for free apps because the store shows no plan cards for them; `pricingSummary` still says "Free". Where a plan is usage-based, `amount` is null and `priceText` carries the store's line.
- `worksWith` is deduplicated. The store adds its own entries for Shopify surfaces ("Shopify Flow", "Shopify Admin") and developers also type free text, so one page can list both "Shopify Flow" and "Flow". Entries that differ only by case or by a leading "Shopify " are collapsed to the store's form, in order of first appearance. Nothing else is normalized; "Klaviyo: Email Marketing" and "Klaviyo: Email Marketing & SMS" are two entries because the store shows two.
- `tagline` is free text the developer wrote and passes through the house free-text filter (`stripContactProse` in the shared `src/scrub.js`) before output: any sentence carrying a phone number, an email address, a name after an honorific or a role, or a licence number is dropped, and `tagline` is null when nothing remains. This is a filter, not a guarantee.
- `launchedAt` is a date, not a timestamp; the store shows only the day.
- Requests are sent from the store's English locale. Translated listings exist under `?locale=` and are not fetched.
- Rate: at most 2 concurrent requests and 24 requests a minute, spaced 2.5 seconds apart rather than sent in a burst. This is a rate the store accepts. Measured on 2026-09-26, the store allows about 65 requests from one address in any two-minute window and answers the rest with HTTP 429, so 30 a minute sits on that edge and the 40 to 60 a minute an earlier build used drew 429s within the first minute; 24 a minute leaves room for the robots.txt fetch, retries and a neighbour on the same address. When a 429 does arrive, the request is retried after a wait of 20, 40 and then 60 seconds, from the same address and under the same identity; nothing is rotated. The measured default run gets zero 429s at this rate. A full leaf category of 400 apps with details on takes about 18 minutes.
- The store's markup changes a few times a year. Listing cards and the app page's structured data (`SoftwareApplication` JSON-LD) are the most stable parts and carry most fields; pricing cards, "Launched", "Languages" and "Works with" are read from labelled blocks and are the most likely to break. When they do, the daily test fails, the status page shows it, a fix ships, and the changelog records it.

### Legal

robots.txt, checked 2026-09-26. For all crawlers, `apps.shopify.com/robots.txt` disallows `/internal/`, `/services/`, any URL containing `q=`, and any URL carrying a `shpxid` or `auth` query parameter. It permits everything else, including the three kinds of page this Actor reads: `/categories/<slug>`, `/categories/<slug>/all?page=N`, and `/<handle>`, plus the category sitemap `/sitemap_categories_en.xml` that robots.txt itself points to. The `q=` disallow covers the store's search, which is why this Actor has no `query` input and never builds a search URL. The crawler reads robots.txt at the start of every run under its own identity and skips anything disallowed.

Shopify's terms. The Shopify Terms of Service (https://www.shopify.com/legal/terms, last updated August 1, 2026), Section 1, item 9, reads: "You agree not to access the Services or monitor any material or information from the Services using any robot, spider, scraper, or other automated means." Those terms bind "the Shopify User", the person or business that registers for a Shopify account or uses a Shopify service under it. Sub Rosa holds no Shopify account and has never logged in; this Actor fetches only logged-out public pages that robots.txt permits, at 24 requests a minute, under the declared identity `SubRosaBot/1.0 (+https://subrosa.dev/bots)`, with no cookies kept and no browser impersonation. If Shopify asks the house to stop, in any form, the Actor is unpublished the same day and the changelog says why.

Personal data. The app page shows individual reviewers' names and review text, and each app links to a Partner page; none of that is collected. The only name-like field is `developerName`, the business name the Partner chose to list under "Developer", carried as the store shows it. The house does not verify whether a listed trading name embeds a person's name; if a Partner lists their studio under their own name, that string is what the store prints and what this field carries. No email addresses, phone numbers, profile URLs or photos are collected, and the test suite fails on any value that looks like one.

Your responsibility. A buyer who holds a Shopify account is bound by the terms they accepted, including the clause above, and is responsible for how they use the data downstream.

### Changelog

- 2026-09-26: house scrub module adopted. `tagline` now passes through the shared `stripContactProse` before output; the live test reads the shared phone and email rules and the schema's identifier keys; `sameDomainDelaySecs` written explicitly as 0 (apps.shopify.com robots.txt states no Crawl-delay, checked 2026-09-26; the 2.5-second spacing is unchanged).
- 2026-09-26: renamed to shopify-app-listings. Fixed identity on the wire (one declared User-Agent on every request, robots.txt fetch included; session pool, header generation and cookie persistence off). Rate lowered to 2 concurrent and 24 requests a minute, evenly spaced; 429s retried in place, never with a new identity. Delivery through createDeliverer, so maxItems is exact. pricingPlans entries now carry amount, currency and period. worksWith deduplicated. Short category slugs resolved through the store's category sitemap. Legal section rewritten with the robots.txt findings and Shopify's terms.
- 2026-09-25: first release.

### Support

Open an issue on the Actor's Issues tab. Replies within one day.

# Changelog

This Actor's version history is a separate document: https://apify.com/subrosa/shopify-app-listings/changelog.md

# Actor input Schema

## `categories` (type: `array`):

Category slugs from apps.shopify.com/categories/<slug>. Leaf categories (for example marketing-and-conversion-marketing-email-marketing) are walked page by page through their full list; top-level and mid-level categories (marketing-and-conversion, store-design) return the curated grid of about 40 apps the page shows. A full category URL is accepted and reduced to its slug.

## `includeDetails` (type: `boolean`):

Visit each app page for developer name, pricing plans, launch date, languages, integrations and the full category list. On by default because the documented default run needs it to produce those fields. Costs one request per app. When off, only the fields on the listing card are returned and the detail fields are null.

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

Stop after this many apps across all categories. The default is sized so the default run finishes in under five minutes.

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

Apify proxy settings. Datacenter proxies are enough for this source; residential proxies are not needed and cost more.

## Actor input object example

```json
{
  "categories": [
    "marketing-and-conversion-marketing-email-marketing",
    "marketing-and-conversion-social-trust-product-reviews"
  ],
  "includeDetails": true,
  "maxItems": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}
```

# Actor output Schema

## `results` (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 = {
    "categories": [
        "marketing-and-conversion-marketing-email-marketing",
        "marketing-and-conversion-social-trust-product-reviews"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": []
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("subrosa/shopify-app-listings").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 = {
    "categories": [
        "marketing-and-conversion-marketing-email-marketing",
        "marketing-and-conversion-social-trust-product-reviews",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": [],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("subrosa/shopify-app-listings").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 '{
  "categories": [
    "marketing-and-conversion-marketing-email-marketing",
    "marketing-and-conversion-social-trust-product-reviews"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": []
  }
}' |
apify call subrosa/shopify-app-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,subrosa/shopify-app-listings"
        }
    }
}
```

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/ji7m2uhjh4THFEURh/builds/Biqn02BcAiTZ0aYDh/openapi.json
