This is the narrow second half of a Shopify image pipeline: the processed asset already exists, and now the system has to publish it. If you still need to choose the source, background recipe, quality gate, or rollout policy, start with the full Shopify background-removal workflow. Here we begin with a durable output object and a specific product-media target.
The safe pattern is additive. Create the new media, wait until Shopify has processed it, verify the result, move it into the intended position, and keep the previous media long enough to roll back. Deleting first makes the workflow look tidy in a diagram and exciting in a storefront if the new image fails to ingest.
The input contract is small but strict: processed object URL or bytes, Shopify product and optional variant IDs, source media ID, target position, alt text, recipe version, and an idempotency key. The rest of this guide stays on that writeback path: GraphQL upload, readiness, reorder, verification, and replay.
GraphQL writeback rule
Add, verify, reorder, and record the resulting IDs.
- Resolve a stable Shopify product ID before uploading anything.
- Use the GraphQL Admin API; the REST Admin API is legacy for new integrations.
- Give Shopify a fetchable output URL or use its staged upload flow for file bytes.
- Wait for asynchronous media processing to reach a usable state.
- Preserve gallery order, alt text, variant associations, and rollback IDs.
01
Define the writeback contract before calling GraphQL
A processed image can become the new primary product image, an additional gallery image, a variant-specific image, or merely a draft asset waiting for approval. Those are different catalog changes. Put the intended action in the job record instead of making the upload node guess from filename order.
Append for review
Add the processed image at the end of the gallery and let a merchant approve it. Lowest automation risk, useful for a first rollout.
Promote to primary
Add the image, wait for readiness, then reorder it to position zero. Keep the previous primary media ID for rollback.
Replace one gallery slot
Map the source media ID to the new media ID, preserve the old position and alt text, then detach the old item after verification.
Associate with variants
Capture existing variant-media relationships before changing anything. A correct product image can still be wrong for a specific color variant.
Use Shopify’s GraphQL product ID as the catalog identity. A handle can change, a title is not unique, and an SKU often belongs to a variant rather than the product itself. If the source system starts from SKU, resolve SKU to variant and product once, then store both IDs on the processing job.
Catalog handoff record
{
"jobId": "shopify_912855135_media_853695510_catalog-v3",
"productId": "gid://shopify/Product/912855135",
"variantIds": ["gid://shopify/ProductVariant/44710001"],
"sourceMediaId": "gid://shopify/MediaImage/853695510",
"action": "replace_gallery_slot",
"targetPosition": 0,
"recipeVersion": "catalog-v3"
}02
Use Shopify’s current media path
For new integrations, use the GraphQL Admin API. Shopify marks the REST Admin API as legacy and points apps toward GraphQL. The app needs the appropriate product and file scopes, and the merchant user still needs permission to update those resources. Shopify’s current product media guide lists the required scopes and supported flow.
Read before writing
- Product ID and current media IDs in display order.
- Alt text and media type for the source slot.
- Variant relationships that reference the source media.
- Existing automation markers or metafields for this source and recipe.
- The current primary image ID so rollback is one known operation.
Take that snapshot immediately before the write, not when the image entered the processing queue. A merchant may reorder or replace photos while your job is running. If the current media state no longer matches the expected source version, stop for review instead of confidently applying yesterday’s plan to today’s product.
03
Give Shopify an image it can actually ingest
A BackgroundErase multipart response is binary image data. Shopify’s product media mutations commonly accept an originalSource URL, so the no-code-friendly route is to upload the processed file to durable object storage first and give Shopify a URL it can fetch without your workflow’s private headers. Keep that object available until Shopify finishes processing.
If the workflow needs to send file bytes directly into Shopify’s file system, use stagedUploadsCreate, upload the file to the returned temporary target with every supplied parameter, and then create the file or product media from the resulting resource URL. Shopify documents this secure two-step flow in the official stagedUploadsCreate reference and fileCreate reference.
External output URL
Simplest when the processed image already lives in S3, R2, a DAM, or another fetchable store. Keep the exact object key in the job record.
Staged upload
Useful when the workflow holds binary data and should upload directly into Shopify. Treat the staging URL and parameters as short-lived credentials.
Do not use a preview page
Drive share pages, signed-in DAM views, and temporary automation download pages may return HTML or expire before Shopify fetches them.
Keep the master
A Shopify CDN copy is a delivery asset. Retain the processed master and recipe outside Shopify if you may regenerate other channels later.
Keep processing and publishing as separate retry domains
Once the processed master exists, a failed Shopify upload should resume from that object. Do not buy or wait for another background-removal request because a catalog mutation, staged upload, or reorder job failed.
04
Add the processed image asynchronously
The simplest GraphQL path for an existing product is productUpdate with a media input. Send the product ID, the processed image URL, media content type, and intentional alt text. Shopify uploads and associates the media asynchronously, so the mutation response is the beginning of the handoff, not the end. The current behavior is documented in Shopify’s productUpdate reference.
Add processed media with productUpdate
mutation AddProcessedImage(
$product: ProductUpdateInput!
$media: [CreateMediaInput!]
) {
productUpdate(product: $product, media: $media) {
product {
id
media(first: 20) {
nodes {
id
alt
mediaContentType
preview { status }
}
}
}
userErrors { field message }
}
}Variables
{
"product": {
"id": "gid://shopify/Product/912855135"
},
"media": [
{
"originalSource": "https://assets.example.com/sku-1842/catalog-v3/master.png",
"alt": "Walnut dining chair on a transparent background",
"mediaContentType": "IMAGE"
}
]
}Check three error surfaces: the HTTP response, top-level GraphQL errors, and mutation-level userErrors. GraphQL can return HTTP 200 while the mutation reports a field or permission problem. Store the returned media ID as soon as it exists. That ID is what later steps reorder, verify, or remove.
05
Wait for Shopify to finish processing
Media ingestion is asynchronous. Poll the returned file or media node until its status is ready, failed, or a sensible deadline is reached. Use increasing delays instead of asking Shopify every second whether it is done. If processing fails, keep the previous product image untouched and retain the stored master so the handoff can retry without rerunning image cleanup.
Readiness query
query CheckProcessedMedia($id: ID!) {
node(id: $id) {
id
... on MediaImage {
alt
status
image { url width height }
}
... on File {
fileStatus
}
}
}Verify before promotion
- Media status reached a ready state rather than processing or failed.
- The image URL exists and dimensions are plausible for the intended recipe.
- Alt text matches the product and does not contain a filename or automation token.
- The product still contains the expected source media and current gallery snapshot.
- The returned media ID is stored on the job before any reorder operation.
Do not delete while processing
A new media ID is not proof of a usable storefront image. Keep the old image in place until Shopify has finished ingesting the new one and your own verification has passed. Empty primary-image slots are memorable in all the wrong ways.
06
Preserve order, alt text, and variants
The first product media item typically acts as the primary image across collection cards, search, and thumbnails. If the processed image should become primary, move it to position zero after it is ready. Shopify provides productReorderMedia for changing positions without deleting and recreating the gallery, and the mutation returns a job you can track. See the current productReorderMedia reference.
Promote processed image to primary
mutation PromoteProcessedImage($productId: ID!, $mediaId: ID!) {
productReorderMedia(
id: $productId
moves: [{ id: $mediaId, newPosition: "0" }]
) {
job { id done }
mediaUserErrors { code field message }
}
}Copy or deliberately rewrite alt text. Background removal changes presentation, not product identity, so the original description is often a good starting point. Avoid “processed image,” “transparent PNG,” or the filename as customer-facing alt text. Describe the product and meaningful view instead.
Variant media needs special care. If the old image represents the blue variant and the new media is meant to replace it, update that association after the media is ready. Record the previous mapping first. Removing a file-product association can also clear variant use of that file, so the rollback plan must include variant IDs, not merely gallery position.
07
Make the catalog write safe to replay
The idempotency key should connect the Shopify product, source media version, and cleanup recipe. Store it in your job database and, if useful, a Shopify metafield. On retry, look up the previously created media ID before calling productUpdate again. Filenames are helpful labels but weak uniqueness rules; duplicate uploads and renamed files happen.
| Value | Why it matters |
|---|---|
| Old primary media ID | Restores the previous storefront image |
| New processed media ID | Prevents duplicate creation and enables removal |
| Old and new positions | Reconstructs gallery order |
| Variant-media mappings | Restores color or style associations |
| Alt text before and after | Avoids metadata loss |
| Processed master object key | Retries Shopify without buying another image-processing call |
A rollback should be a normal job transition, not a panicked manual search. Move the previous media back to its position, restore variant mappings, and mark the processed media as rejected or detached. Delete files only when retention policy says they are no longer needed. Storage is cheap; reconstructing an undocumented product gallery during a campaign is not.
08
Handle Shopify failures without reprocessing the image
Shopify’s GraphQL Admin API uses calculated query cost and returns throttle information in the response extensions. Pace catalog updates from that actual state, and retry throttled or temporary failures with backoff. Shopify’s current limits and response fields are documented in its API limits guide.
| Failure | Retry from | Protect |
|---|---|---|
| Output URL cannot be fetched | Stage or expose the stored master again | Old product media |
| GraphQL user error | Correct input, scope, or product state | Stored master and job snapshot |
| Media processing failed | Create or restage media from stored master | Old gallery order |
| Throttle response | Wait using throttle state, then retry mutation | Idempotency key |
| Reorder job failed | Retry reorder using existing media ID | Both media items |
| Product changed during run | Stop for review and refresh snapshot | Merchant’s newer edits |
Separate image_ready from shopify_published. The first means the processed master exists. The second means Shopify ingested it, the gallery is in the intended order, variant associations are correct, and a final read confirmed the state. If the handoff fails, resume at Shopify. Do not send the source through BackgroundErase again because a catalog mutation had a bad afternoon.
Start with append-only review
For the first production rollout, add processed media at the end of the gallery and require approval. Once the team trusts identity mapping, edge quality, and rollback, automate promotion to primary. A little merchant friction up front is cheaper than confidently replacing the wrong image across 20,000 products.
The safe replacement
Treat product media like catalog data, because it is.
Store the processed master, add new Shopify media, wait for readiness, preserve metadata and variant relationships, and keep the old media until the final read is clean. That sequence is a few steps longer than delete-and-upload and dramatically shorter than explaining a blank storefront.
Plan the full Shopify workflow