DEV Community

Agents001-code
Agents001-code

Posted on

Track your Shopify app competitors: rankings, pricing and new reviews every day

If you build a Shopify app, your competitors are a few clicks away on the same App Store page as you. You can see when one of them drops a price, adds a free plan, picks up the Built for Shopify badge or starts collecting one-star reviews about a broken feature. The problem is that nobody checks ten listings and three category pages by hand every morning for long, and a single look tells you little. What you want is the change: who moved up, who changed their plans, and what merchants said since yesterday.

App developers, product managers, agencies comparing apps for clients, and support teams watching their own reviews all have this problem. This tutorial shows how to collect that change every day with the Shopify App Store Scraper: Apps, Rankings and Reviews Actor on the Apify Store.

Where the data comes from

The Actor reads public pages on apps.shopify.com without logging in. It checks every link against the site's robots.txt before requesting it, waits at least one second between requests and backs off when the site asks it to slow down. It returns three record types into one dataset:

  • App records: name, developer, rating, review count, reviews per star level, pricing plans with prices and features, categories, launch date, languages, integrations ("Works with") and the Built for Shopify badge.
  • Ranking records: every app in a category in the order the App Store lists it, with position, rating, review count, pricing summary and badge, plus the position change since your previous run with the same input.
  • Review records: date, star rating, review text, the reviewing store's name and country as published, time using the app, and the developer's reply.

Reviewers are identified only by the store name the App Store shows. The Actor returns no personal names, emails or profile links.

The Actor is independent and is not affiliated with, endorsed by or sponsored by Shopify. "Shopify" is a trademark of Shopify Inc.

Step 1: Run it once in the Apify Console

Open the Store page (link at the end) and click Start with the example input. You get two app records, the 20 newest reviews of each, and the top 24 apps in the Product reviews category, in about 10 seconds.

Then fill in your own:

  • Apps: a handle such as judgeme or a full link such as https://apps.shopify.com/klaviyo-email-marketing. The handle is the part of the link after apps.shopify.com/.
  • Categories to rank: a category handle or link. Use subcategories such as marketing-and-conversion-social-trust-product-reviews. Top-level categories like marketing-and-conversion only show curated sections and have no ranked list, and the Actor tells you which subcategories to use instead.
  • Keywords (filter rankings): keep only ranked apps whose name, tagline or handle contains a word, for example loyalty. Positions stay the real positions in the category.
  • Maximum reviews per app (10 per page) and Maximum ranked apps per category (24 per page).
  • Only these star ratings: for example 1 and 2 to collect complaints.
  • Maximum records: a total cap across all three record types.

Step 2: Schedule it daily with onlyNew

  1. Switch on Only new items since the previous run (onlyNew). The Actor remembers what it returned for this exact input in a key-value store in your account (shopify-app-store-feed-state by default). Later runs return only reviews it has not seen and apps that newly entered the tracked part of each ranking. App records are always returned, so you can compare ratings and pricing day to day.
  2. Save the input as a task. In Schedules, create a schedule (for example cron 0 7 * * * in your timezone) and add the task.
  3. Connect the dataset to email, Slack, Google Sheets or your own system with an Apify integration or webhook.

The first run returns everything up to your caps. Changing the apps, categories, keywords or review filters starts a fresh history, so settle the lists before you rely on the trend.

One detail matters for rankings. With onlyNew on, apps that were already in the ranking are filtered out, so you only see newcomers. If you want every app's positionChange each day, run a second task with only the category listed and onlyNew off. Keep its app list empty so it has its own history.

Step 3: A daily competitor report in Python

The official apify-client package runs the Actor and reads the results. Install it with pip install apify-client and copy your API token from the Integrations section of the Console.

This script checks three competitors, prints their rating and cheapest paid plan, lists new low-star reviews and shows apps that entered the top 48 of the category.

import os

from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run_input = {
    "apps": ["judgeme", "loox", "okendo-reviews"],
    "categories": ["marketing-and-conversion-social-trust-product-reviews"],
    "maxReviewsPerApp": 50,
    "maxAppsPerCategory": 48,
    "onlyNew": True,
}

run = client.actor("agents001/shopify-app-store-feed").call(
    run_input=run_input,
    max_total_charge_usd=2,
)
if run is None:
    raise SystemExit("Run failed to start or finish")

apps, reviews, rankings = [], [], []
for item in client.dataset(run.default_dataset_id).iterate_items():
    {"app": apps, "review": reviews, "ranking": rankings}[item["recordType"]].append(item)

print("Competitors")
for a in apps:
    paid = [p for p in a["pricingPlans"] if p.get("priceAmount")]
    cheapest = min(paid, key=lambda p: p["priceAmount"])["priceText"] if paid else "none"
    print(f"  {a['name']}: {a['rating']} stars, {a['reviewCount']} reviews, "
          f"cheapest paid plan {cheapest}, Built for Shopify: {a['builtForShopify']}")

print(f"\n{len(reviews)} new reviews")
for r in reviews:
    if r["rating"] <= 2:
        print(f"  {r['appName']} {r['rating']}* {r['storeName']} ({r['storeCountry']}): "
              f"{r['reviewText'] or '[no text]'}")

print("\nNew in the top 48")
for r in rankings:
    print(f"  #{r['position']} {r['appName']} ({r['rating']} stars, {r['reviewCount']} reviews)")
Enter fullscreen mode Exit fullscreen mode

To track movement for every ranked app, run the category on its own with onlyNew off and sort by positionChange, which is positive when an app moved up:

run = client.actor("agents001/shopify-app-store-feed").call(
    run_input={
        "apps": [],
        "categories": ["marketing-and-conversion-social-trust-product-reviews"],
        "maxAppsPerCategory": 96,
    },
    max_total_charge_usd=1,
)
if run is None:
    raise SystemExit("Run failed to start or finish")

rows = list(client.dataset(run.default_dataset_id).iterate_items())
movers = [r for r in rows if r.get("positionChange")]
for r in sorted(movers, key=lambda r: abs(r["positionChange"]), reverse=True)[:10]:
    print(f"{r['appName']}: #{r['previousPosition']} -> #{r['position']}")
Enter fullscreen mode Exit fullscreen mode

previousPosition and positionChange are empty on the first run of a given input. They fill in from the second run on.

What the output looks like

An app record, trimmed:

{
  "recordType": "app",
  "appHandle": "judgeme",
  "name": "Judge.me Product Reviews App",
  "developerName": "Judge.me",
  "rating": 5.0,
  "reviewCount": 48932,
  "ratingDistribution": {"5": 47857, "4": 810, "3": 74, "2": 36, "1": 155},
  "pricingSummary": "Free plan available. Free trial available.",
  "pricingPlans": [
    {"name": "Forever Free", "priceText": "Free", "priceAmount": 0.0},
    {"name": "Awesome", "priceText": "$15/month", "priceAmount": 15.0,
     "currency": "USD", "billingPeriod": "month", "trial": "15-day free trial"}
  ],
  "launchedDate": "2015-06-25",
  "builtForShopify": true
}
Enter fullscreen mode Exit fullscreen mode

A ranking record, trimmed:

{
  "recordType": "ranking",
  "categoryName": "Product review apps",
  "totalAppsInCategory": 486,
  "position": 2,
  "appName": "Entangle Google Reviews",
  "rating": 5.0,
  "reviewCount": 601,
  "pricingSummary": "Free plan available",
  "builtForShopify": true,
  "previousPosition": null,
  "positionChange": null,
  "isNew": true
}
Enter fullscreen mode Exit fullscreen mode

A review record, trimmed:

{
  "recordType": "review",
  "appName": "Judge.me Product Reviews App",
  "rating": 5,
  "reviewDate": "2026-10-22",
  "reviewText": "I asked the Judge.me support team to help display star ratings on my collection pages, and it's now working perfectly. The support agent was helpful and replied quickly. Great support, thank you!",
  "storeName": "ODKcurtains",
  "storeCountry": "Hong Kong SAR",
  "usageDuration": "6 months using the app",
  "developerReply": null,
  "isNew": true
}
Enter fullscreen mode Exit fullscreen mode

What it costs

The Actor uses pay-per-event pricing, with platform usage included:

  • $2.50 per 1,000 app records
  • $2 per 1,000 review records
  • $1.50 per 1,000 ranking records

Take the two daily tasks above. The competitor task returns 3 app records every day ($0.0075) plus whatever new reviews appear. If the three apps get 30 new reviews a day between them, that adds $0.06. The ranking task returns 96 ranking records a day ($0.144). Together that is about $0.21 a day, or about $6.40 over 30 days.

The first run of the competitor task returns up to 50 reviews per app, so up to 150 reviews ($0.30). You can set a maximum charge per run, and the Actor stops cleanly when it is reached and keeps what it returned so far. Maximum records is a second cap. Check the Store page for current pricing.

What to do with the data

  • Competitor tracking: store the daily app records and diff pricingPlans, rating, reviewCount, worksWith and builtForShopify to see when a competitor changes plans, adds an integration or earns the badge.
  • Review monitoring: set Only these star ratings to 1 and 2 on a competitor's app to collect complaints, which often point at features merchants want. Run it on your own app to catch bad reviews and check that each one has a developerReply.
  • Category ranking changes: post to Slack when an app enters the top 24 of your category or moves more than a few places in a day, and chart position over time in Google Sheets.

Limitations

  • There is no keyword search of the App Store. The site's robots.txt asks automated clients not to use the search page, so the Actor does not. Keywords filter category rankings only.
  • Star-only reviews have no text. reviewText is empty for them.
  • Rankings are the App Store's default order at the time of the run, and the order can differ slightly between visitors. Treat small moves as noise.
  • Speed is about one page per second. Reading every review of an app with tens of thousands of reviews takes hours, so keep Maximum reviews per app modest and use onlyNew for ongoing tracking.
  • Prices are as published, which the App Store states in USD.
  • The App Store changes its layout from time to time. If fields that should have values come back empty, report it in the Actor's Issues tab.

Try it

https://apify.com/agents001/shopify-app-store-feed

Top comments (0)