Events that connect you directly to leaders in commerce and Shopify
We’ll be hosting a live AMA on Tuesday, August 20th from 11 am to 1 pm ET that will answer questions on the new GraphQL Product APIs announced in the 2024-04 stable API release.
Hit reply now to post any questions here on this thread before August 20th, 2024 and we’ll answer them live. You can also bring your questions to be answered the day of.
What to know:
The new GraphQL product APIs that support up to 2,000 variants per product were recently launched in the 2024-04 stable API release, enabling developers to build support for larger and more complex catalogs. Alongside the release of the new GraphQL product APIs, we also announced deprecations of the REST product APIs, as well as several fields within the existing GraphQL product APIs.
This AMA is an opportunity to interact with the developers who built these APIs to get any questions on both the new APIs and associated deprecations answered.
In advance of the session, please review the API documentation on the new GraphQL product APIs, our FAQ and our relevant community discussions.
Rules of engagement:
We’ll do our best to follow up on every question during the event.
Solved! Go to the solution
This is an accepted solution.
The AMA is now closed. Questions asked past this time will be moved to the appropriate community board.
Thank you to everyone who joined us for this AMA, and for all your excellent questions. Even though our time is up our team will continue to post answers to the questions that have already been asked. We will do our best to answer them as soon as possible.
Make sure you subscribe to our Community AMAs board to be notified about any future community events.
1. When implementing a data import flow /integration from external systems, is it realistic that a single productSet mutation will be sufficient or would it generally be a safer option (in terms of performance, retry mechanisms, observability, reliability) to use separate APIs to first create the product, then attach variants, then attached medias and metafields, rather than trying to set everything in one go?
2. Will productSet be fully transactional, i.e. either the entire request succeeds or none if it does? In both sync and async mode?
3. Since market APIs can be used to set a fixed price of an item in the default market to a different value than item's price in the store currency, are there plans to deprecate product variant price field at some point? What use cases have you seen where a merchant would want the default market price to be different from product variant price?
Hi @evaldas_92
Is there a plan on the horizon to support inventory and publishing?
It seems not, which makes migrate to graphql almost impossible for large data sets.
@evaldas_92 wrote:is it realistic that a single productSet mutation will be sufficient
thanks this reminds me to test the performance of this vs old api for single variant situations,
For some apps there's a need to create productVariants dynamically for the customer (product personalization etc, draft orders) to be purchased.
And a perf trick is/was basically to make a bunch of placeholder products/variants like a reserve-pool then update one on an as needed basis for checkout usage instead of doing an entire productcreation> variantcreation loop.
Contact paull.newton+shopifyforum@gmail.com for the solutions you need
Save time & money ,Ask Questions The Smart Way
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Thank Paul with a ☕ Coffee for more answers or donate to eff.org
Hello!
We already made the switch to support the 2,000 variants with GraphQL and it's working well.
However, on stores we are doing calls to Shopify Ajax API to get the variants of a product (The prices of the variants are already converted with Market when doing it)
But even with the new version, we receive only 100 variants with no pagination system.
So for the 100 first variants we have the prices converted (for example we have the exact price someone applied to a product for France)
But for the other variants we don't have it so we can't get real time prices.
We're not a sales channel so we can't use the Storefront API.
When will you update it so we can actually get all the variants?
Thank you!
@MathieuDS wrote:We're not a sales channel so we can't use the Storefront API.
That should not be limitation for headless, that should only be a limitation IF making a public app, to operate as sales-channel...
https://shopify.dev/docs/storefronts/headless/getting-started/build-options#the-headless-channel
https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/getting-started
https://apps.shopify.com/headless
One reference clarification from shopify:
Contact paull.newton+shopifyforum@gmail.com for the solutions you need
Save time & money ,Ask Questions The Smart Way
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Thank Paul with a ☕ Coffee for more answers or donate to eff.org
There are many existing stores that allow you to order things like custom t-shirts that leak customer information via the /collections JSON endpoint, where every product is always visible. I’ve seen examples of stores that leak photos, addresses, personal messages, etc in this way.
For our use case we need customers to be able to create their own products based on a file they upload.
Can the variant system be used for this in a way that keeps all custom data private?
I'd recommend not creating unique products based on customer inputs, since product creation is not storefront activity. Any apps that do this are likely to cause leaking of sensitive data, and I'd recommend against using them.
Ideally the customizations a customer make to a product land on the line item properties and metafields.
Is there any more information that make the above not workable?
We have an app block that takes a customer's file and sends it over to our server for analysis (we're a manufacturing company creating physical objects based on clients' designs). After this we need to store the file and analysis, so we save them into a meta object (as it contains too much info for a line item, and also includes some files our server generates).
When adding to the cart we create a new product and link the the meta object to it, so we have access to the data without exposing it to others (as meta objects are private).
This all works, but it's so convoluted, and we can't use things like the product image in the cart, because that image will get exposed to the public endpoints (and the image would contain our clients' design which we want to keep private).
Still hoping Shopify will implement a 'private' flag on products at some point, hiding them from all the public endpoints and only allowing access via a direct product ID in the API. That would solve so many issues. Really don't understand why all products should be visible on the JSON endpoints.
Thanks for the added details - makes sense why Line Item properties don't neccessarily handle the use case.
I'd recommend using the sales channels that the products belong to to your advantage. For instance, creating the product you need internally, but not adding it to any public facing sales channels like Online Store.
I understand that you'd still need the product to show for that one customer in the cart, but perhaps that is just a thin representation using line item properties for appearances only.
Then using line item properties you can tie the real hidden product's id to your line item, and then use Shopify Flow to add it to the order after it's placed, that way it's never exposed and stays unique to the customer.
Still a bit convoluted, but privacy is important.
Hi Javi,
There are several options to sell custom products. For most custom products, buyer information should only be stored on the cart (line item attributes, metafields etc).
With your additional context, you may be able to Shopify's B2B functionality, available on plus plans. B2B allows products to be published to narrower audiences.
Another potential workaround is to use draft orders. You could create a draft with a custom product in it and then send that to a client as an invoice.
We’ll take into consideration the spirit of the problems you’ve surfaced.
@javl wrote:(as meta objects are private)
metaobjects have a webpage feature, make sure to put in place process, or automation to very that "private" really stays private
https://help.shopify.com/en/manual/custom-data/metaobjects/webpages
Contact paull.newton+shopifyforum@gmail.com for the solutions you need
Save time & money ,Ask Questions The Smart Way
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Thank Paul with a ☕ Coffee for more answers or donate to eff.org
@javl wrote:we can't use things like the product image in the cart
During the /cart step, before checkout, shouldn't the custom-image come from data in the metaobject(MOBS) through a theme customization and not on a public product itself?
So don't set the custom-image as the products/variants featured-image, set a placeholder or reuse the image used on the standard uncustomized product.
UX: This does mean a dissonance when going to checkout since line items will show their feature-image and checkout is not customizable like a theme is.
IF on a shopify Plus plan:
For /checkout line-item images a shopify function cartTransform should enable replacing the line-items featured-image with a custom-image from a metafield ; not sure if MOBS are accessible in the functions query schema.
Contact paull.newton+shopifyforum@gmail.com for the solutions you need
Save time & money ,Ask Questions The Smart Way
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Thank Paul with a ☕ Coffee for more answers or donate to eff.org
Hi @javl the ajax JSON leak has been an quite a lowkey but major issue for a decade and I've never seen a solution that works when using the online-sales channel.
At minimum require customer accounts for the entire store, and any api under your control should have some sort of authentication system to associate to an actual customer.
edit: 💣 This does not solve other logged in customers accounts poking around the apis, but it's a roadbump. After that it's a matter of trying to at least obfuscate the info, either by hashing it, or breaking it up in ways that can only be re-assembled using info from the target customers data.
The only actual fix if your in this area of concern is going headless, and fully managing your own frontend stack; and thus endpoints.
Especially if you are in any regulated field or even partially tangential(medical, regulated goods,etc)
Contact paull.newton+shopifyforum@gmail.com for the solutions you need
Save time & money ,Ask Questions The Smart Way
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Thank Paul with a ☕ Coffee for more answers or donate to eff.org
Hi
We currently use REST API's published_at field on the Product to hide sold-out products from online store channel and publish back-in-stock products to the online store channel.
Since the REST API product endpoint is being deprecated we are rewriting our app logic using GraphQL.
But in the GraphQL productUpdate mutation (2024-10), it says publishedAt field is deprecated and asks us to Use PublishablePublish instead. This means we have to re-authorize all existing customers with the write_publications scope
We are extremely worried that we will not be able to re-authorize 100% of our customers. Because most customers have our app on auto-pilot trusting it to do its job. Likely scenario is only 10% re-authorize which will be a disaster for our app that has been around for over 10 years.
Back in 2018, when multi-location was rolled-out by Shopify, app developers were given the ability to backfill the new scopes : read_inventory, write_inventory and read_locations. See screenshot attached showing how it was done.
As you are taking away the publish ability by deprecating the REST endpoints, it would only be fair to give automatic access to its equivalent in GraphQL to ensure smooth migration. Since our existing customers have already given us "publish" permission by installing our app, can you please enable back-population of the new access scopes necessitated by this deprecation similar to what was done for the multi-location roll-out in 2018. This is a practical solution that works for all stakeholders.
This issue has been raised by other developers as well in the previous AMA.
Appreciate this very much @AsafGitai
How can I track this request? Will we get an email from Shopify?
@AsafGitai Can you update us on the request to backfill write_publications scope from a month back?
Thanks in advance!
Thanks @AsafGitai for following through with this request!
Shopify has now given an option to backfill read/write_publications. We need to support these scopes in code and fill out a form
See latest AMA reply: https://community.shopify.com/c/community-amas-ask-me-anything/shopify-community-ama-with-shopify-de...
Hi @Naren1 Thank you for your response & raising this query to Shopify as well.
We are currently using the REST API in our live apps, and to date, the REST API has never required any additional scopes to publish a product in any sales channel, particularly the online store sales channel. Our apps have been live and functioning without the "published_at" scope.
However, we have noticed that the GraphQL API now requires this scope to publish a newly created product via API. Since our apps are built using REST API-based code and scopes, we do not currently have the "published_at" scope. We do, however, have the "read_products" and "write_products" scopes. Could you please allow all developers to access the write_publications scope if they have the "write_products" scope? Without this, we and other developers will face issues, as product publication is closely tied to product creation. We believe it would be appropriate to provide this scope in such cases.
I hope our situation is clear, and we look forward to your assistance @AsafGitai in acquiring this new scope.
Hi @Ajay_399 ,
> Could you please allow all developers to access the write_publications scope if they have the "write_products" scope
Yes, we just ask that you fill the request form.
Hi,
Thank you for your response. We will proceed with filling out the Publishing Permissions Request.
However, our main concern is the statement that present in the Shopify Publishing Permissions Request Form:
"If your app currently reads or writes published_at/published_scope via REST, this permission backfill will grant read_publications and write_publications to all existing app-store authentication tokens. Those permissions will only be granted if the app currently has read_products and write_products scopes."
Screenshot - https://prnt.sc/wrxBJKX4KAmL
As explained in my previous message, the REST API does not require specific publishing scopes, as it manages publications with the write_products scope alone.
Given this, I request that developers be allowed to collect the write_publications scope when they have the write_products scope, even if they are not using published_at/published_scope.
Please clarify this, and thank you for your time and consideration.
Question 1:
For retrieving the total number of products, we previously used the products/count endpoint in the REST API. What is the recommended alternative in the new GraphQL product APIs for fetching the total product count?
Question 2:
In our current implementation, we rely on the REST API’s Product object within Webhooks. Will the new GraphQL product APIs accommodate similar functionality with the Product object? Additionally, will updated documentation be provided, particularly since the current documentation for the product/update webhook (Webhooks Documentation) still references the REST API?
Question 3:
We currently use the REST API’s Product object in Bulk Operations. As we transition to the new GraphQL product APIs, how will the Product object be supported in Bulk Operations? Will there be comprehensive documentation available to guide this transition? Currently, some fields from the GraphQL Product object do not work in Bulk Operations as they do with the REST API’s Product object.
Here is an example of our current GraphQL query used in Bulk Operations:
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
handle
publishedAt
media(first: 1) {
edges {
node {
preview {
image {
originalSrc
}
}
}
}
}
variants(first:100) {
edges {
node {
sku
barcode
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
Specifically, can we expect all fields from the GraphQL Product object to be functional in Bulk Operations?
Hi @Oleksandra_vino ,
Question1:
You can achieve this in GraphQL by using the productsCount query. It currently has a limit of 10,000 but we will have an update on that soon.
Question2:
There is an equivalent object in GraphQL, for which the documentation can be found here.
At this time, webhooks will continue to use the Product resource as their base. We’re assessing that and making updates there, too!
Question3:
There is parity between the GraphQL and REST responses. What fields are struggling with?
Hi,
Regarding Question3: I’m encountering an issue with a Bulk Operation query. The following query works correctly when fetching data for a single product:
{
product(id: "gid://shopify/Product/9550098661667") {
resourcePublicationsV2(first: 50, catalogType: MARKET) {
edges {
node {
publication {
id
catalog {
title
... on MarketCatalog {
markets(first: 50) {
edges {
node {
id
name
handle
}
}
}
}
}
}
}
}
}
}
}
Here is the response:
{
"data": {
"product": {
"resourcePublicationsV2": {
"edges": [
{
"node": {
"publication": {
"id": "gid://shopify/Publication/244715815203",
"catalog": {
"title": "Algeria",
"markets": {
"edges": [
{
"node": {
"id": "gid://shopify/Market/77692600611",
"name": "Algeria",
"handle": "algeria"
}
}
]
}
}
}
}
}
]
}
}
}
}
However, when I attempt a similar query in a Bulk Operation, it returns an error:
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
handle
resourcePublicationsV2(catalogType: MARKET, first: 250) {
edges {
node {
publication {
id
catalog {
title
... on MarketCatalog {
markets(first: 50) {
edges {
node {
id
name
handle
}
}
}
}
}
}
}
}
}
publishedAt
media(first: 1) {
edges {
node {
preview {
image {
originalSrc
}
}
}
}
}
variants(first:10) {
edges {
node {
sku
barcode
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
The error message is:
{
"data": {
"bulkOperationRunQuery": {
"bulkOperation": null,
"userErrors": [
{
"field": [
"query"
],
"message": "The parent 'node' field for a nested connection must select the 'id' field without an alias and must be of 'ID' return type. Connection fields without 'id': resourcePublicationsV2."
}
]
}
}
}
Interestingly, when I exclude the following section from the query, it works fine:
... on MarketCatalog {
markets(first: 50) {
edges {
node {
id
name
handle
}
}
}
}
Here is the modified query that works without issues:
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
handle
resourcePublicationsV2(catalogType: MARKET, first: 250) {
edges {
node {
publication {
id
catalog {
title
}
}
}
}
}
publishedAt
media(first: 1) {
edges {
node {
preview {
image {
originalSrc
}
}
}
}
}
variants(first:10) {
edges {
node {
sku
barcode
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
This behavior suggests that the part handling MarketCatalog and markets works differently in a single product query versus a Bulk Operation. Could you please provide guidance on how to resolve this issue and ensure consistent behavior across both query types?
Question about product and variant counts:
1. productsCount is returning only upto 10,000 count. We need to know the exact number of products in a shop like the REST api endpoint currently does. This also goes for other counts that are limited to 10,000.
2. we need variantsCount ie. the total number of variants in a shop. the unified Count object does not have this presently. Note that Product.variantsCount gives only the variant count for a given product. I'm referring to the the "total" variantsCount of the entire shop. the variants/count.json REST endpoint returns the total variant count of a shop but that is being deprecated.
Hi @Naren1
Hello,
For creating a product with multiple variants, is it possible to do it using a single mutation?
What's the exact use case for productSet and productCreate/productVariantsBulkCreate mutations?
I am trying to create a product with more than 100 variants using productSet, but can't find inventoryItem in prodctSet.variants (ProductVariantSetInput)
So for creating a new product with variant fields like tracking, weight etc, do I have to use productCreate and then create variants using productVariantsBulkCreate?
I see inventoryItem in productVariantsBulkCreate though (ProductVariantInput)
Thanks,
Lily
Hello, Lily!
Yes, it is possible to create a product with multiple variants, depending on the use case. We have written a (hopefully) helpful guide on how to migrate to our new Product model here.
productSet does not support inventoryItemInput so you would need to use productCreate & productVariantsBulkCreate mutations in that use case. We are looking into extending the capabilities of productSet in future versions. There is also an inventoryItemUpdate mutation which has the same inputs, but operates on one InventoryItem at a time.
Hello Team,
I share the same concern as @Naren1 and regarding the need to re-authorize all existing customers with the write_publications scope.
We manage 4 public apps that use automations and webhooks for creating and updating products based on our app functionalities. The issue is that if users don’t access the app, we can’t update the app scopes & it will stope & break the app automations. Therefore, I strongly request that publishing products be allowed under the existing write_products scope.
Please avoid introducing a new scope like write_publications. If it’s unavoidable, could you provide a workaround so that existing access tokens can continue publishing products using the write_products scope? For new app users, we will of course request the write_publications scope.
Additionally, I’m concerned about the efficiency of the GraphQL API compared to REST. In REST, we could add and publish a product with a single HTTP request. However, in GraphQL, the same process requires 3 HTTP calls:
While REST handled this with fewer requests and less complexity, GraphQL seems to make the process longer and more complicated.
Moreover, adding tags and creating or updating variants also require separate mutations. Could we have a single master mutation that allows us to create a product with basic parameters, all in one HTTP call?
Could you please look into this? Many other developers share these concerns as well. Any assistance would be appreciated.
Thank you.
Hi @Ajay_399 ,
Thanks for this feedback, as mentioned to Naren1 regarding scope increases, this is something we are considering.
Hi @AsafGitai ,
Thanks for your reply.
Additionally, I’m concerned about the efficiency of the GraphQL API compared to REST. In REST, we could add and publish a product with a single HTTP request. However, in GraphQL, the same process requires 3 HTTP calls:
productCreate mutation
publishablePublish mutation
Fetching publicationId with another mutation
While REST handled this with fewer requests and less complexity, GraphQL seems to make the process longer and more complicated.
Moreover, adding tags and creating or updating variants also require separate mutations. Could we have a single master mutation that allows us to create a product with basic parameters, all in one HTTP call?
Could you please look into this? Thanks.
@Ajay_399 Shopify has given an option to backfill read/write_publications. You need to support these scopes in code and fill out a form
See latest AMA reply: https://community.shopify.com/c/community-amas-ask-me-anything/shopify-community-ama-with-shopify-de...
I've been experiencing an issue with the productVariantsBulkCreate mutation, specifically when using the REMOVE_STANDALONE_VARIANT strategy. Despite this setting, the default variant is still being created (using the first option and value defined for the product) and not removed as expected. When I contacted your API team, they mentioned they couldn't replicate the issue. However, I've seen multiple discussions in forums where others have encountered the same problem. The current workaround—allowing Shopify to create the default variant, then renaming and removing it manually before adding the desired variants—seems far from ideal. Is this a known issue, or am I overlooking something?
Additionally, could this issue be avoided by using the productSet mutation to immediately create the product with the respective options and variants? If productSet doesn't create the default variant, this might be a better approach for me. What I would like is more freedom with productSet like setting the inventory location id as this is not an option for now...
Hi @LaytonBerth ,
We’ve seen this conversation through support and have not been able to reproduce. Please follow up on the current support ticket you have.
Also, can you please share links to the other discussions on the topic you are referring to?
Yes, you could use productSet, but it does not support inventoryItemInput, we are looking into extending the capabilities of productSet in future versions
In the Admin REST API we had the field `presentment_prices` in Variant which used to return price of product with different currencies. In the graphql API this has been replaced with `contextualPricing` in ProductVariant but earlier this was a list and now it is just a Object.
How can I get presentment_prices for all currencies using graphql API given that I don't know all the currencies beforehand ?
Any suggestions here ?
Hello!
Thanks for your question, we will get back to you on this.
Hello and thanks for your question. I've added a similar response in this forum.
"One thing to note is that you'll now need to pass country code as the context input argument, rather than currency code. The reason is that you can have multiple countries that share the same currency (for example France and Spain), but that have different final prices. You'll be able to see the currency code off of the price."
To fetch the available countries, you can use the following queries:
In Admin API
query Markets {
markets(first: 10) {
nodes {
regions(first: 10) {
nodes {
... on MarketRegionCountry {
code
}
}
}
}
}
}
In Storefront API
query AvailableCountries {
localization {
availableCountries {
currency { isoCode }
isoCode
}
}
}
Is there a way to just get all the contextualPricing without passing the countries ?
No, there is not a way to fetch them in bulk via the Admin API at this time. A bulk operation using aliasing may be the best option for this.
Why does productSet mutation not have the ProductSetInput.variants.inventoryItem field, just like ProductVariantsBulkCreateInput? It makes the mutation unusable for me. Let us at least set the location it should be stocked at. Otherwise I need to fire off 4 extra mutations per variant just to:
This just seems incredibly convoluted to me 😞
Hello!
We have heard feedback from lots of partners that this is something they would consider very helpful. We are currently looking into the best way to allow inventory to work with productSet.
We were initially concerned that including too much scope into productSet would impact our ability to give a satisfactory level of performance in the API. As we continue to improve things we believe that this concern will no longer be relevant.
Hi @EfstathiosS thanks for your response.
Is there a workaround for this flow? I cannot use productSet because of the number of followup mutations I need to do per variant.
Hello, no problem, thanks for your engagement.
There is not a current workaround for this, however we are looking into extending the capabilities of the inventory mutations.
Hi, seems like you answered a workaround in this thread for someone else: https://community.shopify.com/c/community-amas-ask-me-anything/shopify-community-ama-with-shopify-de...
I should be using productCreate without passing any variants. And then using productVariantsBulkCreate with strategy: REMOVE_STANDALONE_VARIANT. This allows me to create the product with correct options and optionValues in 1 mutation, and then add its variants in a single followup mutation that also provides the fulfillment service location ID, and their starting quantities. That way I only need to fire 2 mutations per product.
I hope we see the ability to provide a starting variants.inventory.locationId in productSet soon.
2m ago Learn the essential skills to navigate the Shopify admin with confidence. T...
By Shopify Feb 12, 2025Learn how to expand your operations internationally with Shopify Academy’s learning path...
By Shopify Feb 4, 2025Hey Community, happy February! Looking back to January, we kicked off the year with 8....
By JasonH Feb 3, 2025