Carmentara

How to track your Shopify app's keyword rankings daily (App Store SEO)

By the Carmentara team

Row of small off-white tiles of different heights, with one copper tile standing taller than its neighbours.

Stop guessing your App Store SEO performance. Track organic position history for your app and competitors automatically, for under $2 a month.

Most merchants find apps by typing a few words into the Shopify App Store search box: "email marketing", "upsell", "abandoned cart". Where your app lands in those results decides whether merchants see it at all. But Shopify's Partner Dashboard shows installs, merchants and earnings, not your organic position for a keyword. The only keyword reports Shopify gives you are for paid App Store ads.

So if you change your listing title, ship a big release or see a competitor climb, you have no record of what happened to your rank and when.

This guide covers two levels:

  1. Free: check by hand
  2. Least effort: a scheduled Apify actor that builds the rank history for you

Pick the level that fits you. If you track two or three keywords, level 1 may be enough.

Level 1: Check by hand (free, 5 minutes a day)

  1. Open a private browser window, so you see what a logged-out visitor sees.
  2. Search apps.shopify.com for each of your keywords.
  3. Count down to your app. Skip cards marked Ad, because they're paid placements, not organic rank.
  4. Write the position, the date and the top competitors into a spreadsheet.

This works, but it's easy to miscount once you're past the first page, and nobody keeps it up every day for 15 keywords. Results can also differ between a logged-in merchant and a private window.

What about a script of your own?

You could script it yourself. The App Store has no public search API, though, so a script has to read the search pages, and that's where the work is. Shopify changes the markup of those pages without notice, rate-limits repeated requests and blocks traffic it doesn't like. A tracker that worked last month can quietly return nothing, or the wrong positions. On top of that you need pagination, ad handling, stored history and a scheduler, plus someone to fix it when it breaks. It's doable, but it's a small product you then have to maintain.

Level 2: A scheduled actor that keeps the history

We built and maintain that tracker as an Apify actor, so you don't have to: Shopify App Store Keyword Rank Tracker & Scraper. Its keyword-ranks mode returns where any app ranks in App Store search for your keywords. What it does:

  • Reads up to 240 organic results per keyword (24 = the first page) across pages, with polite delays and retries.
  • Counts organic positions only. Ads are flagged separately (isSponsored, sponsoredSlots) and never shift the count.
  • Gives you one target row per keyword × tracked app, including "found": false when the app isn't in the scanned results.
  • Remembers the previous run, so each row has previousPosition and rankChange (positive = moved up).
  • Needs no Shopify account or API key.
Diagram: search keywords and app handles go into the Shopify App Store Keyword Rank Tracker, which runs once a day as an Apify task with a schedule. It writes rank rows (keyword, app, position, rankChange) that feed Google Sheets in append mode, rank alerts filtered on rankChange, and a Python chart from rank_history.py.
One run a day adds one row per keyword and app, and the rows become your rank history.

Pricing: $0.002 per keyword-rank row, plus a $0.00005 start fee per run at the default 512 MB. There's no monthly fee, and platform usage isn't charged separately. For example, tracking 10 keywords for your app and 2 competitors with Only output tracked apps on is 30 rows a day. Over a 30-day month that's 900 rows × $0.002 = $1.80, plus $0.0015 in start fees.

Apify's free plan includes $5 a month in credit ("$5 to spend in Apify Store or on your own Actors"), and no credit card is required (Apify pricing). That covers the example above, but only while your total Apify use for the month, this actor plus anything else you run, stays under $5. Unused credit doesn't roll over to the next month.

No coding required

You can do the whole daily setup in the Apify Console, without writing any code:

  1. Open the actor in the Apify Console. In the input form, set Mode to keyword-ranks, fill in Search keywords and Your / competitor apps to track, and turn on Only output tracked apps.
  2. Click Save as a new task and run it once.
  3. Add a daily schedule for the task under Schedules (Apify schedules).

The code below does the same thing, if you'd rather script it.

Run it from code

Python, using the official apify-client package (version 3 or later):

Python
# pip install "apify-client>=3"
import os

from apify_client import ApifyClient

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

run_input = {
    "mode": "keyword-ranks",
    "keywords": ["email marketing", "sms marketing", "abandoned cart"],
    "targetAppHandles": ["omnisend", "klaviyo-email-marketing"],  # your app + competitors
    "onlyTargetApps": True,       # one row per keyword x tracked app (cheapest)
    "maxResultsPerKeyword": 48,   # scan the first two pages
}

run = client.actor("carmentara/shopify-app-intel").call(run_input=run_input)

for item in client.dataset(run.default_dataset_id).iterate_items():
    r = item["keywordRank"]
    where = f"#{r['position']}" if r["found"] else f"not in top {r['scannedResults']}"
    print(f"{r['keyword']:<16} {r['handle']:<26} {where:<16} change: {r['rankChange']}")

Output from our test run on 4 October 2026 (the client also streams the run log first):

Bash
# email marketing  omnisend                   #2               change: 0
# email marketing  klaviyo-email-marketing    #1               change: 0
# sms marketing    omnisend                   #3               change: 0
# sms marketing    klaviyo-email-marketing    #1               change: 0
# abandoned cart   omnisend                   not in top 48    change: None
# abandoned cart   klaviyo-email-marketing    not in top 48    change: None
Grid of organic positions for two tracked apps on 4 October 2026. For "email marketing", omnisend is #2 and klaviyo-email-marketing is #1. For "sms marketing", omnisend is #3 and klaviyo-email-marketing is #1. Neither app is in the top 48 for "abandoned cart".
The same run as the output above, as a grid: one cell per keyword and tracked app.

change is None on the first run for a keyword and when an app wasn't found. The same input works in the Apify Console form, so you don't need code to start.

What a row looks like

A real target row from the same day:

JSON
{
  "mode": "keyword-ranks",
  "timestamp": "2026-10-04T14:50:14.907Z",
  "keywordRank": {
    "keyword": "email marketing",
    "rowType": "target",
    "position": 2,
    "previousPosition": 2,
    "rankChange": 0,
    "page": 1,
    "pagePosition": 2,
    "isSponsored": false,
    "handle": "omnisend",
    "name": "Omnisend Email Marketing & SMS",
    "rating": 4.7,
    "reviews": 3182,
    "pricingText": "Free plan available",
    "builtForShopify": false,
    "isTarget": true,
    "found": true,
    "sponsoredSlots": [],
    "scannedResults": 24,
    "totalResults": 3996,
    "url": "https://apps.shopify.com/omnisend",
    "searchUrl": "https://apps.shopify.com/search?q=email+marketing"
  }
}

Turn Only output tracked apps off and you also get one result row for every app in the scanned results, in order. That's useful for seeing which competitors sit above you, but each of those rows is also billed at $0.002.

Top five organic Shopify App Store results on 4 October 2026 for three keywords, with review counts. Email marketing: klaviyo-email-marketing, omnisend, ecomsend, mailchimp, emailwiz (3,995 apps match). Upsell: bundle-deals, upsell-cross-sell-kit-1, essential-post-purchase-upsell, bundlex, essential-cart-drawer (3,131 match). Product reviews: judgeme, air-reviews, trustshop, loox, junip (7,457 match). The app with the most reviews is not always #1.
With "Only output tracked apps" off, you see who ranks around you, here the top 5 for three keywords.

One limitation to know about: Shopify doesn't show ads to the servers Apify runs on, so sponsoredSlots is normally empty. Organic positions aren't affected.

Make it daily

  1. In the Apify Console, open the actor, enter the input above and click Save as a new task.
  2. On the task, add a Schedule that runs once a day, for example 0 7 * * * in your timezone. See Apify schedules.
  3. Keep the keyword list stable. Each run compares with the previous one for the same keyword, and each run's dataset becomes one day in your history.

Chart your rank history in Python

This script collects the target rows from your last 60 successful runs and draws one line per keyword and app:

Python
# pip install "apify-client>=3" pandas matplotlib
import os

import matplotlib
matplotlib.use("Agg")  # write a PNG, no display needed
import matplotlib.pyplot as plt
import pandas as pd
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
actor = client.actor("carmentara/shopify-app-intel")

# Your last 60 successful runs of the actor (scheduled or manual), newest first.
runs = actor.runs().list(desc=True, limit=60, status="SUCCEEDED").items

rows = []
for run in runs:
    for item in client.dataset(run.default_dataset_id).iterate_items():
        r = item.get("keywordRank")
        if item.get("mode") != "keyword-ranks" or r["rowType"] != "target":
            continue
        rows.append({
            "date": item["timestamp"][:10],
            "keyword": r["keyword"],
            "app": r["handle"],
            "position": r["position"],  # None = not found in the scanned results
        })

df = pd.DataFrame(rows)
if df.empty:
    raise SystemExit("No keyword-rank target rows yet: run keyword-ranks mode with targetAppHandles first.")
df["position"] = pd.to_numeric(df["position"])  # None -> NaN (a gap in the chart)

# One value per day, keyword and app (the latest run of the day wins).
history = (
    df.drop_duplicates(["date", "keyword", "app"], keep="first")  # runs are newest first
      .pivot(index="date", columns=["keyword", "app"], values="position")
      .sort_index()
)
history.to_csv("rank_history.csv")
print(history.tail(10))

ax = history.plot(marker="o", figsize=(10, 5), title="Shopify App Store keyword rank (1 = top)")
ax.invert_yaxis()  # rank 1 at the top
ax.set_ylabel("Organic position")
plt.tight_layout()
plt.savefig("rank_history.png")
print("Saved rank_history.csv and rank_history.png")

If you only want the runs of one task, replace the runs = ... line with runs = client.task("your-username/your-task-name").runs().list(desc=True, limit=60, status="SUCCEEDED").items. Dates are in UTC.

Or pull today's ranks into a spreadsheet

Every run's results are available as CSV. This gets the latest successful run of your task, one row per keyword × app:

Bash
curl -fsS "https://api.apify.com/v2/actor-tasks/your-username~your-task-name/runs/last/dataset/items?status=SUCCEEDED&format=csv&fields=timestamp,keywordRank&unwind=keywordRank" \
  -H "Authorization: Bearer $APIFY_TOKEN" > todays-ranks.csv

In Google Sheets, the same URL works with =IMPORTDATA("...&token=YOUR_APIFY_TOKEN"). Keep in mind that anyone who can edit the sheet can see the token. To build a history in Sheets instead of a daily snapshot, add Apify's Google Sheets integration to the task in append mode, so each run adds its rows below the previous ones.

Get an alert when a rank moves. Apify's Slack integration and webhooks fire on run events, such as a run that succeeded or failed. On their own, they tell you that a run finished, not that a rank changed. To get an alert only when rankChange isn't 0, or when an app drops out of the scanned results (found: false), route the run's dataset through Zapier, Make or n8n. Trigger on the finished task run, fetch the dataset items, add a filter (Zapier filters, Make filters, n8n Filter node), then send the matching rows to Slack, Discord or email. rankChange is empty when an app wasn't found, so check found as well.

Tips for useful tracking

  • Track the words merchants type, not your brand name. Start with your category's head terms ("email marketing"), then the specific jobs ("abandoned cart email", "back in stock alert").
  • Add two or three competitors per keyword. Your own rank means more when you can see who moved around you.
  • Scan deep enough. If you're usually on page 2 or 3, set maxResultsPerKeyword to 48 or 72 so you get a number instead of "not found".
  • Write down your listing changes. Put the date of every title, subtitle or screenshot change next to the chart, so you can tell which change moved the rank.
  • Watch the trend, not one day. A one-place move for a day is noise. A drop that holds for a week is worth a look.

Ready to automate your Shopify App Store SEO tracking?

For two or three keywords, a private window and a spreadsheet work. For a daily rank history of your app and your competitors that you don't have to maintain:

  1. Open the Shopify App Store Keyword Rank Tracker & Scraper on Apify.
  2. Pick keyword-ranks mode and enter your keywords and app handles.
  3. Schedule it daily. For small setups like the 10-keyword example above, it's covered by Apify's free $5 monthly credit.

Questions or feature requests? Open an issue on the actor's Issues tab.