Store installs
One row per store that installed your app — first-touch attribution (channel, surface, keyword), install and uninstall timestamps, uninstall reasons, the current plan and trial state, and shop-admin details. GET /api/v1/apps/:app/store-installs returns a paginated object: "list" built for exporting your full install base into a warehouse. Requires the metrics:read scope.
Store installs come from your Shopify Partner API integration. If the integration was never configured for the app, the list is simply empty (a 200, not an error). Fields that haven't been captured for a store come back as null rather than being dropped.
Store installs
Returns the app's stores as an object: "list", newest install first. Each row is a single store with its first-touch attribution, install/uninstall lifecycle, current plan and trial state, and shop-admin details. has_more tells you when to fetch the next page.
By default only currently-installed stores are returned. Pass status=all to return every store regardless of status — this is the way to pull the complete install base in one pass. For a warehouse export, prefer cursor pagination (see Pagination).
Path parameter
- Name
app- Type
- string
- Description
The team app's ULID, e.g.
01JN4HKQX0000000000000000.
Query parameters
- Name
status- Type
- string
- Description
Install-status filter:
INSTALLED(default),UNINSTALLED,CLOSED,FROZEN, orallto return every store regardless of status.allis the way to pull the complete install base in one pass. Any other value returns a422.
- Name
channel- Type
- string
- Description
Filter by first-touch traffic channel, e.g.
App Store AdsorOrganic Search.
- Name
installed_after- Type
- string
- Description
YYYY-MM-DD. Only stores installed on or after this date.
- Name
installed_before- Type
- string
- Description
YYYY-MM-DD. Only stores installed on or before this date.
- Name
include_test- Type
- boolean
- Description
Include test / development stores. Defaults to
false(they are excluded).
- Name
cursor- Type
- string
- Description
Opt-in cursor pagination. An opaque token, maximum 64 characters; start empty and read
next_cursorfrom the response. See Pagination.
- Name
page- Type
- integer
- Description
The page to return. Minimum
1.
- Name
per_page- Type
- integer
- Description
Rows per page,
1–100.
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/store-installs \
-H "Authorization: Bearer rk_live_..." \
-d status=all \
-d channel="App Store Ads" \
-d per_page=100
Response
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/store-installs",
"currency": "USD",
"page": 1,
"per_page": 100,
"total_count": 1284,
"has_more": true,
"metadata": {},
"data": [
{
"shop_domain": "acme-store.myshopify.com",
"shop_id": "5271523",
"install_source": "App Store Ads",
"install_surface": "search_ad",
"install_keyword": "inventory sync",
"first_touch_at": "2026-05-12T18:03:00+00:00",
"uninstall_reasons": [],
"uninstall_reason_description": null,
"installed_at": "2026-05-14T09:15:00+00:00",
"uninstalled_at": null,
"status": "INSTALLED",
"on_trial": false,
"trial_ends_at": null,
"plan_name": "Growth",
"is_shopify_plus": false,
"is_partner_dev_store": false,
"shop_owner_name": "Jane Merchant",
"primary_domain_url": "https://acme-store.com",
"currency_code": "USD",
"iana_timezone": "America/New_York",
"admin_country_code": "US",
"country": "United States",
"city": "Brooklyn",
"province": "New York",
"company": null,
"store_created_at": "2024-11-02T14:22:00+00:00",
"is_test": false,
"team_apps": {}
}
]
}
Response fields
The list is the shared object: "list" envelope; each item in data is a store-install row.
List envelope (object: "list")
- Name
object- Type
- string
- Description
Always
"list".
- Name
url- Type
- string
- Description
The endpoint path for this resource.
- Name
currency- Type
- string
- Description
The reporting currency for the list, e.g.
USD.
- Name
page- Type
- integer
- Description
The current page number (1-based).
nullin cursor mode.
- Name
per_page- Type
- integer
- Description
Rows per page.
- Name
total_count- Type
- integer
- Description
Total stores across all pages, after filters.
nullin cursor mode.
- Name
has_more- Type
- boolean
- Description
Whether further pages exist.
- Name
next_cursor- Type
- string
- Description
Present only in cursor mode: the token to pass as
cursorfor the next page, ornullwhen there are no more rows.
- Name
metadata- Type
- object
- Description
Reserved metadata object for the list.
- Name
data- Type
- array
- Description
The store-install rows for this page.
Store-install row
Each field is null unless noted.
- Name
shop_domain- Type
- string
- Description
The
*.myshopify.comdomain of the store.
- Name
shop_id- Type
- string
- Description
The Shopify shop id.
- Name
install_source- Type
- string
- Description
First-touch traffic channel that led to the install, e.g.
App Store AdsorOrganic Search.
- Name
install_surface- Type
- string
- Description
The surface the first touch occurred on, e.g.
search_ad.
- Name
install_keyword- Type
- string
- Description
The search keyword attributed to the first touch, when known.
- Name
first_touch_at- Type
- string
- Description
ISO-8601 timestamp of the store's first touch.
- Name
uninstall_reasons- Type
- array
- Description
Why the store left, from Shopify's uninstall survey — one entry per uninstall (a reinstall cycle produces several). Each entry has the same structure as the Customers endpoint's
uninstall_reasons: anuninstalled_attimestamp, a multi-selectreasonsarray of{ "code", "label" }, and a free-textdetail.[]when the store never uninstalled or never answered the survey. See Customers for the full field description.
- Name
uninstall_reason_description- Type
- string
- Description
The free-text detail the merchant typed on their most recent uninstall, when any.
- Name
installed_at- Type
- string
- Description
ISO-8601 install timestamp.
- Name
uninstalled_at- Type
- string
- Description
ISO-8601 timestamp of the most recent uninstall, or
nullwhile still installed.
- Name
status- Type
- string
- Description
One of
INSTALLED,UNINSTALLED,CLOSED, orFROZEN.
- Name
on_trial- Type
- boolean
- Description
Whether the store is actively on a trial.
- Name
trial_ends_at- Type
- string
- Description
ISO-8601 trial end timestamp, or
null.
- Name
plan_name- Type
- string
- Description
The store's current plan name.
- Name
is_shopify_plus- Type
- boolean
- Description
Whether the store is on Shopify Plus.
- Name
is_partner_dev_store- Type
- boolean
- Description
Whether the store is a Partner development store.
- Name
shop_owner_name- Type
- string
- Description
The store owner's name.
- Name
primary_domain_url- Type
- string
- Description
The store's primary storefront URL.
- Name
currency_code- Type
- string
- Description
The store's currency code, e.g.
USD.
- Name
iana_timezone- Type
- string
- Description
The store's IANA timezone, e.g.
America/New_York.
- Name
admin_country_code- Type
- string
- Description
Two-letter country code from the shop admin, e.g.
US.
- Name
country- Type
- string
- Description
The store's country name.
- Name
city- Type
- string
- Description
The store's city.
- Name
province- Type
- string
- Description
The store's province / state.
- Name
company- Type
- string
- Description
The store's company name, when known.
- Name
store_created_at- Type
- string
- Description
ISO-8601 timestamp of when the Shopify store was created.
- Name
is_test- Type
- boolean
- Description
Whether this is a test / development store.
- Name
team_apps- Type
- object
- Description
Other apps of yours that this same store has installed. Keyed by app; describe your own apps' presence per store.
{}when the store has installed no other app of yours.
Pagination
By default the list is offset-paginated: use page and per_page (1–100) to walk the result set, and check has_more to know when to stop.
The endpoint also supports opt-in cursor pagination, which is the recommended way to export the full install base into a warehouse (e.g. BigQuery). Pass cursor (start empty), read next_cursor from the response, and pass it back as cursor on the next request; repeat until next_cursor is null (equivalently, until has_more is false). Cursor mode is stable under concurrent inserts and is not subject to the page-mode row cap. In cursor mode page and total_count come back null.
Errors
Beyond the universal 401 / 403 / 422 / 429 (see Errors):
- The list never
404s — an app with no configured Partner API integration, or no stores matching your filters, returns an emptydatalist (a200). - An unknown
statusor a malformed date surfaces as422 validation_failed.