How Shopify app scopes work
Scopes are granted once, during OAuth. When you click Install, Shopify redirects you to the app, the app asks Shopify for a specific list of scopes, Shopify shows you that list, and your approval produces an access token tied to those scopes and nothing else. If the app later calls an endpoint outside its scopes, the Admin API returns a 403 and the request fails. The app cannot quietly expand its own access; requesting a new scope means sending you back through the approval screen.
Scopes come in read and write pairs for most resources. read_products lets an app list products, variants, images, collections and their metadata. write_products lets it create, update and delete those same objects. Similar pairs exist for orders, customers, inventory, fulfillments, discounts, themes, content and so on. There are dozens, but for a product imagery app only the product pair matters.
| Scope | What it grants | Needed by an image tool? |
|---|---|---|
read_products | List and search products, variants, images, collections | Yes — to show your catalog |
write_products | Create/update/delete products, images, alt text, positions | Yes — to push images back |
read_orders | Order history, line items, shipping addresses | No |
read_customers | Customer names, emails, addresses, tags | No |
write_themes | Edit theme files and Liquid templates | No |
read_inventory | Stock levels by location | Rarely |
A useful mental model: scopes are not a security score, they are a description of the job. Match the job the app claims to do against the scopes it requests, and the mismatches become obvious.
What read_products and write_products actually cover
The product scopes are broader than the name suggests, and merchants often underestimate both what they include and what they exclude.
Included in read_products: product titles, descriptions, handles, tags, product type, vendor, status (active/draft/archived), all variants with their SKUs and prices, every product image with its URL, alt text and position, collections and their membership rules, and product metafields. Note that prices are product data, not order data. An app with read access to products can see what you charge.
Included in write_products: everything above, but editable. That includes adding a new image to a product, changing an image's alt text, reordering the gallery, deleting an image, and, less obviously, changing titles, prices and publishing status. An image app with write_products could edit a price; a well-built one will only touch the images sub-resource, but the scope itself does not enforce that distinction.
Not included in either: orders, customers, discounts, inventory levels, payouts, shop settings, themes and storefront code. A product-scoped app cannot see your revenue, your customer list, or your checkout.
Shopify phrases scopes in plain language on the approval page: "View products" and "Edit products" rather than the raw scope names. If the list also shows "View orders", "View customers" or "Edit your Online Store", the app is asking for more than an image workflow needs. That is the moment to ask why.
This is the exact access the Retouchable Shopify integration requests: read_products to populate the product picker and write_products to push finished images back with a filename, alt text and gallery position. It does not request order, customer or payment scopes, because a photo tool has no use for them.
Why over-scoped apps are a real risk, not a theoretical one
Two things make excess scopes worth caring about. The first is that access tokens are long-lived. Once you approve read_customers, the app holds a token that can pull your customer list at any time, for as long as the app stays installed, whether or not the feature that supposedly needed it is ever used. A breach at the app vendor becomes a breach of whatever their token could reach.
The second is that Shopify's own review process only checks that requested scopes are plausibly justified, not that every feature actually requires them. Plenty of apps request a wide set of scopes at launch "in case" a future feature needs them, because narrowing scopes later is free but widening them forces every merchant back through re-approval.
The good news is that the enforcement is hard. An app scoped to products physically cannot fetch orders; the API refuses. So a minimal scope list is not a promise of good behaviour, it is a technical ceiling on what bad behaviour could reach. That is why reading the list matters more than reading the privacy policy.
What a product image app does with write_products
It helps to see the write scope in terms of specific API calls rather than the abstract "edit products" label. A well-designed imagery integration uses write_products for a narrow set of operations:
- Attach an image to a product. Upload the finished file and link it to the product ID you picked. The app sets the filename here, which is worth caring about for image SEO.
- Set alt text. Written at upload time so the image is accessible and indexable from the moment it goes live, rather than left blank for someone to fix later.
- Set the position. Position 1 is the featured image, the one Shopify uses in collection grids, in-store search results and most theme cards. An integration that can write position lets you swap a hero image without opening the admin.
- Optionally, remove or replace an image. Useful for bulk refreshes, and the reason write access is needed at all.
Manual admin workflow
- Download the finished image
- Open the product in Shopify admin
- Upload, wait, drag to position 1
- Click into the image to add alt text
- Repeat per product
Scoped app push
- Pick the product from the in-app picker (read scope)
- Push with filename, alt text and position set (write scope)
- Image lands featured, labelled and searchable
- No order or customer data involved at any step
Notice what is absent: nothing in that workflow touches a price, a title or a variant. The integration could, under the scope, but it has no reason to and a well-built one won't. When evaluating an app, ask the vendor plainly which fields it writes. A clear answer ("images, alt text and position, nothing else") is a good sign.
Rate limits and what they mean for bulk pushes
Scopes determine what an app can do; rate limits determine how fast. Shopify's Admin API throttles every app per store, using a leaky-bucket for REST (roughly two requests per second on standard plans, with a burst allowance) and a cost-based budget for GraphQL. When an app exceeds the limit, Shopify returns a 429 with a Retry-After header saying how long to wait.
This matters for merchants because a bulk image refresh across a few hundred products is exactly the kind of job that hits the limit. An app that ignores 429s will fail part-way and leave your catalog half-updated. An app that reads Retry-After and backs off will finish, just more slowly. If you are pushing a large batch, expect it to be paced rather than instant, and prefer a tool that reports which products succeeded.
These are illustrative timings, not benchmarks, but the shape is reliable: a scoped, rate-aware push is minutes, and manual is a working day. For more on planning the batch itself, see bulk-updating Shopify product images.
Disconnecting, uninstalling, and what happens to your data
Scopes cover the install; the other half of the trust question is the exit. There are two different actions and they are not equivalent.
Disconnecting inside the app removes the stored access token on the app's side. The app can no longer call your store, but Shopify still lists the app as installed until you remove it from the admin. This is the right move if you want to re-link a different store or pause an integration without losing your workspace.
Uninstalling from Shopify admin revokes the token at Shopify's end immediately. Shopify then sends the app an app/uninstalled webhook. A compliant app verifies that webhook's HMAC signature, deletes the stored connection, and purges any store data it was holding. Shopify also requires every public app to handle three mandatory privacy webhooks (customers/data_request, customers/redact, shop/redact) so that a merchant's or customer's data can be exported or erased on request, 48 hours after uninstall for the shop-level redaction.
| Action | Token revoked | App data purged | Shopify webhook sent |
|---|---|---|---|
| Disconnect in app | Yes (app side) | Connection only | No |
| Uninstall in admin | Yes (Shopify side) | Yes, on webhook | app/uninstalled + shop/redact |
Two practical checks: after uninstalling, the app should not appear in your admin's app list and any "connection status" page in the app should show disconnected. And regardless of scope, the app should be storing your access token encrypted at rest, since the token is the key to everything the scope allows. Ask the vendor if that is not stated.
A five-point checklist before you approve any product app
- Read the scope list on the install screen. Map each line to a feature you actually want. "View products" and "Edit products" for an image tool is correct. Anything about orders, customers, or the online store is a question to ask before clicking.
- Ask which fields the app writes.
write_productsis broad. The answer you want is a short, specific list: images, alt text, position. - Check how it handles rate limits. If you plan bulk pushes, ask whether partial batches report per-product success.
- Find the disconnect control. It should be visible inside the app, not buried in a support email.
- Confirm the uninstall behaviour. Token revoked, data purged, privacy webhooks handled. A vendor who can answer that in one sentence has thought about it.
Scopes are the only enforceable statement of what an app can touch. For product imagery the right answer is two scopes, both about products, and nothing about your orders or customers. If the install screen says more than that, the app is asking for more than the job needs.