If you build for the Shopify ecosystem — or just research it — you eventually want the App Store as data: app ratings, review counts, pricing, and the actual review text. The problem is there's no official public Shopify App Store API, and the listing pages are a moving target. Roll your own scraper and you'll spend more time chasing layout changes than analyzing data.
In this tutorial we'll pull Shopify App Store data three ways — app details, reviews, and catalog discovery — using a hosted actor and a few lines of Python. No API key for Shopify, no login, no headless-browser babysitting.
What we'll build
- Fetch full details for a list of apps (rating, review count, pricing, developer).
- Pull reviews for an app, including the reviewing store's country and the developer's reply.
- Discover apps across the whole catalog by keyword — handy for competitor research.
We'll call the Shopify App Store Scraper actor on Apify via the official apify-client. The actor handles pagination, retries, and the brittle parts; you just read JSON.
Prerequisites
- Python 3.8+
- A free Apify account (for the API token)
- The Apify client:
pip install apify-client
Grab your API token from Settings → Integrations in the Apify console. Keep it out of source control — read it from an environment variable.
export APIFY_TOKEN="apify_api_xxx"
1. Get app details
The actor's input is a small JSON object. Set mode to details and pass one or more appHandles — the handle is the slug at the end of an app URL (https://apps.shopify.com/klaviyo-email-marketing → klaviyo-email-marketing).
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run_input = {
"mode": "details",
"appHandles": [
"klaviyo-email-marketing",
"judgeme-product-reviews",
],
}
# Run the actor and wait for it to finish
run = client.actor("freshactors/shopify-app-store-scraper").call(run_input=run_input)
# Read the results from the run's dataset
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"{item['title']:40} ⭐ {item['rating']} ({item['reviewCount']} reviews) — {item['pricingSummary']}")
Each record looks like this:
{
"_type": "app_details",
"_schemaVersion": "1.0",
"handle": "klaviyo-email-marketing",
"url": "https://apps.shopify.com/klaviyo-email-marketing",
"title": "Klaviyo: Email Marketing & SMS",
"developer": "Klaviyo",
"category": "DeveloperApplication",
"rating": 4.6,
"reviewCount": 2805,
"pricingSummary": "Free to install",
"builtForShopify": false,
"icon": "https://cdn.shopify.com/app-store/listing_images/.../icon.png",
"_scrapedAt": "2026-06-01T08:00:00.000Z"
}
The details come from the page's application/ld+json structured-data block, which is far more stable than scraping CSS classes — so this keeps working even when Shopify reshuffles the markup.
2. Pull reviews (with country and developer replies)
Switch mode to reviews. You can cap volume with maxReviewsPerApp and order results with reviewsSort (newest, highest_rating, or lowest_rating).
run_input = {
"mode": "reviews",
"appHandles": ["klaviyo-email-marketing"],
"maxReviewsPerApp": 500,
"reviewsSort": "lowest_rating", # surface complaints first
}
run = client.actor("freshactors/shopify-app-store-scraper").call(run_input=run_input)
reviews = list(client.dataset(run["defaultDatasetId"]).iterate_items())
print(f"Fetched {len(reviews)} reviews")
# Quick complaint mining: show 1-star reviews and where they came from
for r in reviews:
if r["rating"] <= 2:
print(f"[{r['rating']}★ {r['country']}] {r['storeName']}: {r['body'][:120]}")
A review record carries the full text plus useful context:
{
"_type": "review",
"_schemaVersion": "1.0",
"handle": "klaviyo-email-marketing",
"reviewId": "2186287",
"rating": 5,
"storeName": "Bellaforma Jewelry",
"country": "United States",
"usedAppFor": "Over 1 year using the app",
"date": "May 1, 2026",
"body": "We've seen significant revenue growth through dialed-in flows...",
"developerReply": null,
"_scrapedAt": "2026-06-01T08:00:00.000Z"
}
Because the actor treats an empty-but-200 review page as a soft failure and retries with backoff, you won't get a misleading "0 reviews" when a request just hiccuped.
3. Discover apps across the catalog
Doing competitor research? discover mode walks Shopify's official catalog sitemap and returns full details for apps matching a keyword. Use maxApps to cap how many to enrich.
import pandas as pd
run_input = {
"mode": "discover",
"query": "email marketing",
"maxApps": 50,
}
run = client.actor("freshactors/shopify-app-store-scraper").call(run_input=run_input)
apps = list(client.dataset(run["defaultDatasetId"]).iterate_items())
# Build a competitive landscape table, sorted by rating
df = pd.DataFrame(apps)[["title", "developer", "rating", "reviewCount", "pricingSummary"]]
df = df.sort_values("reviewCount", ascending=False)
print(df.head(10).to_string(index=False))
In a few seconds you have a ranked table of email-marketing apps — rating, review count, developer, and pricing — ready for a spreadsheet or a notebook. Leave query empty to enumerate the catalog from the top.
Tip: don't block on the run
.call() waits for the run to finish, which is fine for small jobs. For big pulls, start the run and stream results as they land:
# Fire and forget; poll later
started = client.actor("freshactors/shopify-app-store-scraper").start(run_input=run_input)
print("Run id:", started["id"])
You can also export the dataset directly to CSV/Excel/JSON from the Apify console, or schedule recurring runs (e.g. a daily review pull) with Apify Schedules.
What about cost?
The actor is pay-per-result, so a quick estimate: app details are $0.002 each, discovery results $0.001 each, and reviews $0.0001 each. Pulling details for 100 apps is about $0.20; 20,000 reviews is about $2.00. (Apify platform usage is billed separately.)
Wrapping up
With one hosted actor and the apify-client, you can turn the Shopify App Store into structured JSON — details, reviews, or a whole-catalog competitor map — without an API key or a brittle homegrown scraper. The actor is monitored by a daily canary, so when Shopify changes its pages it gets patched fast instead of silently dying on you.
If you want to try it, the actor lives here: Shopify App Store Scraper on Apify. Have a Shopify-data question or hit an edge case? Drop it in the comments — happy to help.
Top comments (0)