# product - storefront - QUERY Version: 2024-04 ## Description Fetch a specific `Product` by one of its unique attributes. ### Access Scopes ## Arguments * [handle](/docs/api/storefront/2024-04/scalars/String): String - The handle of the `Product`. * [id](/docs/api/storefront/2024-04/scalars/ID): ID - The ID of the `Product`. ## Returns * [availableForSale](/docs/api/storefront/2024-04/scalars/Boolean): Boolean! Indicates if at least one product variant is available for sale. * [compareAtPriceRange](/docs/api/storefront/2024-04/objects/ProductPriceRange): ProductPriceRange! The [compare-at price range](https://help.shopify.com/manual/products/details/product-pricing/sale-pricing) of the product in the shop's default currency. * [createdAt](/docs/api/storefront/2024-04/scalars/DateTime): DateTime! The date and time when the product was created. * [description](/docs/api/storefront/2024-04/scalars/String): String! A single-line description of the product, with [HTML tags](https://developer.mozilla.org/en-US/docs/Web/HTML) removed. * [descriptionHtml](/docs/api/storefront/2024-04/scalars/HTML): HTML! The description of the product, with HTML tags. For example, the description might include bold `` and italic `` text. * [featuredImage](/docs/api/storefront/2024-04/objects/Image): Image The featured image for the product. This field is functionally equivalent to `images(first: 1)`. * [handle](/docs/api/storefront/2024-04/scalars/String): String! A unique, human-readable string of the product's title. A handle can contain letters, hyphens (`-`), and numbers, but no spaces. The handle is used in the online store URL for the product. * [id](/docs/api/storefront/2024-04/scalars/ID): ID! A globally-unique ID. * [isGiftCard](/docs/api/storefront/2024-04/scalars/Boolean): Boolean! Whether the product is a gift card. * [metafield](/docs/api/storefront/2024-04/objects/Metafield): Metafield A [custom field](https://shopify.dev/docs/apps/build/custom-data), including its `namespace` and `key`, that's associated with a Shopify resource for the purposes of adding and storing additional information. * [metafields](/docs/api/storefront/2024-04/objects/Metafield): Metafield! A list of [custom fields](/docs/apps/build/custom-data) that a merchant associates with a Shopify resource. * [onlineStoreUrl](/docs/api/storefront/2024-04/scalars/URL): URL The product's URL on the online store. If `null`, then the product isn't published to the online store sales channel. * [options](/docs/api/storefront/2024-04/objects/ProductOption): ProductOption! A list of product options. The limit is defined by the [shop's resource limits for product options](/docs/api/admin-graphql/latest/objects/Shop#field-resourcelimits) (`Shop.resourceLimits.maxProductOptions`). * [priceRange](/docs/api/storefront/2024-04/objects/ProductPriceRange): ProductPriceRange! The minimum and maximum prices of a product, expressed in decimal numbers. For example, if the product is priced between $10.00 and $50.00, then the price range is $10.00 - $50.00. * [productType](/docs/api/storefront/2024-04/scalars/String): String! The [product type](https://help.shopify.com/manual/products/details/product-type) that merchants define. * [publishedAt](/docs/api/storefront/2024-04/scalars/DateTime): DateTime! The date and time when the product was published to the channel. * [requiresSellingPlan](/docs/api/storefront/2024-04/scalars/Boolean): Boolean! Whether the product can only be purchased with a [selling plan](/docs/apps/build/purchase-options/subscriptions/selling-plans). Products that are sold on subscription (`requiresSellingPlan: true`) can be updated only for online stores. If you update a product to be subscription-only (`requiresSellingPlan:false`), then the product is unpublished from all channels, except the online store. * [seo](/docs/api/storefront/2024-04/objects/SEO): SEO! The [SEO title and description](https://help.shopify.com/manual/promoting-marketing/seo/adding-keywords) that are associated with a product. * [tags](/docs/api/storefront/2024-04/scalars/String): String! A comma-separated list of searchable keywords that are associated with the product. For example, a merchant might apply the `sports` and `summer` tags to products that are associated with sportwear for summer. Updating `tags` overwrites any existing tags that were previously added to the product. To add new tags without overwriting existing tags, use the GraphQL Admin API's [`tagsAdd`](/docs/api/admin-graphql/latest/mutations/tagsadd) mutation. * [title](/docs/api/storefront/2024-04/scalars/String): String! The name for the product that displays to customers. The title is used to construct the product's handle. For example, if a product is titled "Black Sunglasses", then the handle is `black-sunglasses`. * [totalInventory](/docs/api/storefront/2024-04/scalars/Int): Int The quantity of inventory that's in stock. * [trackingParameters](/docs/api/storefront/2024-04/scalars/String): String URL parameters to be added to a page URL to track the origin of on-site search traffic for [analytics reporting](https://help.shopify.com/manual/reports-and-analytics/shopify-reports/report-types/default-reports/behaviour-reports). Returns a result when accessed through the [search](https://shopify.dev/docs/api/storefront/current/queries/search) or [predictiveSearch](https://shopify.dev/docs/api/storefront/current/queries/predictiveSearch) queries, otherwise returns null. * [updatedAt](/docs/api/storefront/2024-04/scalars/DateTime): DateTime! The date and time when the product was last modified. A product's `updatedAt` value can change for different reasons. For example, if an order is placed for a product that has inventory tracking set up, then the inventory adjustment is counted as an update. * [variantBySelectedOptions](/docs/api/storefront/2024-04/objects/ProductVariant): ProductVariant Find a product’s variant based on its selected options. This is useful for converting a user’s selection of product options into a single matching variant. If there is not a variant for the selected options, `null` will be returned. * [vendor](/docs/api/storefront/2024-04/scalars/String): String! The name of the product's vendor. ## Examples ### Retrieve a single product Curl example: "curl -X POST \\\nhttps://your-development-store.myshopify.com/api/2024-04/graphql.json \\\n-H 'Content-Type: application/json' \\\n-H 'X-Shopify-Storefront-Access-Token: {storefront_access_token}' \\\n-d '{\n\"query\": \"query getProductById($id: ID!) { product(id: $id) { title } }\"\n}'\n" Node example: "const client = new shopify.clients.Storefront({\n domain: 'your-development-store.myshopify.com',\n storefrontAccessToken,\n});\nconst data = await client.query({\n data: `query getProductById($id: ID!) {\n product(id: $id) {\n title\n }\n }`,\n});\n" Ruby example: null Remix example: "const { storefront } = await unauthenticated.storefront(\n 'your-development-store.myshopify.com'\n);\n\nconst response = await storefront.graphql(\n `#graphql\n query getProductById($id: ID!) {\n product(id: $id) {\n title\n }\n }`,\n);\n\nconst data = await response.json();\n" Graphql query: "query getProductById($id: ID!) {\n product(id: $id) {\n title\n }\n}" #### Graphql Input null #### Graphql Response { "data": { "product": { "title": "Camper Van" } } } ### Retrieve product media Curl example: "curl -X POST \\\nhttps://your-development-store.myshopify.com/api/2024-04/graphql.json \\\n-H 'Content-Type: application/json' \\\n-H 'X-Shopify-Storefront-Access-Token: {storefront_access_token}' \\\n-d '{\n\"query\": \"query getProductMedia($id: ID!) { product(id: $id) { id media(first: 10) { edges { node { mediaContentType alt ...mediaFieldsByType } } } } } fragment mediaFieldsByType on Media { ... on ExternalVideo { id embeddedUrl } ... on MediaImage { image { url } } ... on Model3d { sources { url mimeType format filesize } } ... on Video { sources { url mimeType format height width } } }\"\n}'\n" Node example: "const client = new shopify.clients.Storefront({\n domain: 'your-development-store.myshopify.com',\n storefrontAccessToken,\n});\nconst data = await client.query({\n data: `query getProductMedia($id: ID!) {\n product(id: $id) {\n id\n media(first: 10) {\n edges {\n node {\n mediaContentType\n alt\n ...mediaFieldsByType\n }\n }\n }\n }\n }\n \n fragment mediaFieldsByType on Media {\n ... on ExternalVideo {\n id\n embeddedUrl\n }\n ... on MediaImage {\n image {\n url\n }\n }\n ... on Model3d {\n sources {\n url\n mimeType\n format\n filesize\n }\n }\n ... on Video {\n sources {\n url\n mimeType\n format\n height\n width\n }\n }\n }`,\n});\n" Ruby example: null Remix example: "const { storefront } = await unauthenticated.storefront(\n 'your-development-store.myshopify.com'\n);\n\nconst response = await storefront.graphql(\n `#graphql\n query getProductMedia($id: ID!) {\n product(id: $id) {\n id\n media(first: 10) {\n edges {\n node {\n mediaContentType\n alt\n ...mediaFieldsByType\n }\n }\n }\n }\n }\n \n fragment mediaFieldsByType on Media {\n ... on ExternalVideo {\n id\n embeddedUrl\n }\n ... on MediaImage {\n image {\n url\n }\n }\n ... on Model3d {\n sources {\n url\n mimeType\n format\n filesize\n }\n }\n ... on Video {\n sources {\n url\n mimeType\n format\n height\n width\n }\n }\n }`,\n);\n\nconst data = await response.json();\n" Graphql query: "query getProductMedia($id: ID!) {\n product(id: $id) {\n id\n media(first: 10) {\n edges {\n node {\n mediaContentType\n alt\n ...mediaFieldsByType\n }\n }\n }\n }\n}\n\nfragment mediaFieldsByType on Media {\n ... on ExternalVideo {\n id\n embeddedUrl\n }\n ... on MediaImage {\n image {\n url\n }\n }\n ... on Model3d {\n sources {\n url\n mimeType\n format\n filesize\n }\n }\n ... on Video {\n sources {\n url\n mimeType\n format\n height\n width\n }\n }\n}" #### Graphql Input null #### Graphql Response { "data": { "product": { "id": "gid://shopify/Product/929898465", "media": { "edges": [ { "node": { "mediaContentType": "IMAGE", "alt": "", "image": { "url": "https://cdn.shopify.com/s/files/1/0003/2595/3821/products/draft58.jpg?v=1683592994" } } }, { "node": { "mediaContentType": "IMAGE", "alt": "", "image": { "url": "https://cdn.shopify.com/s/files/1/0003/2595/3821/products/draft59.jpg?v=1683592994" } } } ] } } } } ### Retrieve local prices for a product Curl example: "curl -X POST \\\nhttps://your-development-store.myshopify.com/api/2024-04/graphql.json \\\n-H 'Content-Type: application/json' \\\n-H 'X-Shopify-Storefront-Access-Token: {storefront_access_token}' \\\n-d '{\n\"query\": \"query ProductPricing @inContext(country: CA) { product(handle: \\\"wool-sweater\\\") { variants(first: 1) { nodes { price { amount currencyCode } } } } }\"\n}'\n" Node example: "const client = new shopify.clients.Storefront({\n domain: 'your-development-store.myshopify.com',\n storefrontAccessToken,\n});\nconst data = await client.query({\n data: `query ProductPricing @inContext(country: CA) {\n product(handle: \"wool-sweater\") {\n variants(first: 1) {\n nodes {\n price {\n amount\n currencyCode\n }\n }\n }\n }\n }`,\n});\n" Ruby example: null Remix example: "const { storefront } = await unauthenticated.storefront(\n 'your-development-store.myshopify.com'\n);\n\nconst response = await storefront.graphql(\n `#graphql\n query ProductPricing @inContext(country: CA) {\n product(handle: \"wool-sweater\") {\n variants(first: 1) {\n nodes {\n price {\n amount\n currencyCode\n }\n }\n }\n }\n }`,\n);\n\nconst data = await response.json();\n" Graphql query: "query ProductPricing @inContext(country: CA) {\n product(handle: \"wool-sweater\") {\n variants(first: 1) {\n nodes {\n price {\n amount\n currencyCode\n }\n }\n }\n }\n}" #### Graphql Input null #### Graphql Response { "data": { "product": { "variants": { "nodes": [ { "price": { "amount": "90.0", "currencyCode": "CAD" } } ] } } }, "extensions": { "context": { "country": "CA", "language": "EN" } } } ### Load translated and localized content for a product Curl example: "curl -X POST \\\nhttps://your-development-store.myshopify.com/api/2024-04/graphql.json \\\n-H 'Content-Type: application/json' \\\n-H 'X-Shopify-Storefront-Access-Token: {storefront_access_token}' \\\n-d '{\n\"query\": \"query ProductTitle @inContext(country: CA, language: FR) { product(handle: \\\"wool-sweater\\\") { title description } }\"\n}'\n" Node example: "const client = new shopify.clients.Storefront({\n domain: 'your-development-store.myshopify.com',\n storefrontAccessToken,\n});\nconst data = await client.query({\n data: `query ProductTitle @inContext(country: CA, language: FR) {\n product(handle: \"wool-sweater\") {\n title\n description\n }\n }`,\n});\n" Ruby example: null Remix example: "const { storefront } = await unauthenticated.storefront(\n 'your-development-store.myshopify.com'\n);\n\nconst response = await storefront.graphql(\n `#graphql\n query ProductTitle @inContext(country: CA, language: FR) {\n product(handle: \"wool-sweater\") {\n title\n description\n }\n }`,\n);\n\nconst data = await response.json();\n" Graphql query: "query ProductTitle @inContext(country: CA, language: FR) {\n product(handle: \"wool-sweater\") {\n title\n description\n }\n}" #### Graphql Input null #### Graphql Response { "data": { "product": { "title": "Chandail en laine", "description": "C’est très chaud!" } }, "extensions": { "context": { "country": "CA", "language": "FR" } } } ### Load products which are published in a given context Curl example: "curl -X POST \\\nhttps://your-development-store.myshopify.com/api/2024-04/graphql.json \\\n-H 'Content-Type: application/json' \\\n-H 'X-Shopify-Storefront-Access-Token: {storefront_access_token}' \\\n-d '{\n\"query\": \"query Products @inContext(country: GB) { woolSweater: product(handle: \\\"wool-sweater\\\") { title } alarmClock: product(handle: \\\"alarm-clock\\\") { title } products(first: 2) { nodes { title } } }\"\n}'\n" Node example: "const client = new shopify.clients.Storefront({\n domain: 'your-development-store.myshopify.com',\n storefrontAccessToken,\n});\nconst data = await client.query({\n data: `query Products @inContext(country: GB) {\n woolSweater: product(handle: \"wool-sweater\") {\n title\n }\n alarmClock: product(handle: \"alarm-clock\") {\n title\n }\n products(first: 2) {\n nodes {\n title\n }\n }\n }`,\n});\n" Ruby example: null Remix example: "const { storefront } = await unauthenticated.storefront(\n 'your-development-store.myshopify.com'\n);\n\nconst response = await storefront.graphql(\n `#graphql\n query Products @inContext(country: GB) {\n woolSweater: product(handle: \"wool-sweater\") {\n title\n }\n alarmClock: product(handle: \"alarm-clock\") {\n title\n }\n products(first: 2) {\n nodes {\n title\n }\n }\n }`,\n);\n\nconst data = await response.json();\n" Graphql query: "query Products @inContext(country: GB) {\n woolSweater: product(handle: \"wool-sweater\") {\n title\n }\n alarmClock: product(handle: \"alarm-clock\") {\n title\n }\n products(first: 2) {\n nodes {\n title\n }\n }\n}" #### Graphql Input null #### Graphql Response { "data": { "woolSweater": { "title": "Wool sweater" }, "alarmClock": null, "products": { "nodes": [ { "title": "Wool sweater" } ] } }, "extensions": { "context": { "country": "GB", "language": "EN" } } }