This page explains how to:
- Apply scopes
- Structure GraphQL requests
- Check if resources exist
- Achieve Reference Expansion
- Determine query complexity
- Perform advanced queries for dynamic Project data and searching
The GraphQL API is versionless, meaning new types and fields may be introduced at any time without notice. As a result, dynamic schema stitching is discouraged, as it can lead to naming conflicts and unexpected behavior.
Interactive GraphQL console
Scopes
Use case | GraphQL service | Scope |
---|---|---|
query for a particular resource | Query.{resourceType} | view_{resourceType}s:{projectKey} |
query for resources of a certain type | Query.{resourceType}s | view_{resourceType}s:{projectKey} |
create a resource of a certain type | Mutation.create{resourceType} | manage_{resourceType}s:{projectKey} |
update a particular resource | Mutation.update{resourceType} | manage_{resourceType}s:{projectKey} |
delete a particular resource | Mutation.delete{resourceType} | manage_{resourceType}s:{projectKey} |
manage_products:{projectKey}
is required for updating a Product with the Mutation.updateProduct
service. The view_products:{projectKey}
scope would not be sufficient for this.view_published_products:{projectKey}
scope can be used by the Query.products
service to retrieve data in masterData.current
, but not in masterData.staged
. The same applies for the Query.productProjectionSearch
service that only returns data with this scope when the staged
parameter is set to false
in such queries.Query.inStore
requires view_{resourceType}s:{projectKey}:{storeKey}
.Store-scoped queries and mutations
Query for resources in Stores
inStore
and inStores
to query resources belonging only to specified Stores.query {
inStore(key: "luxury-brand") {
carts {
results { id }
total
}
}
}
query {
inStores(keys: ["luxury-brand", "budget-brand"]) {
carts {
total
}
}
}
Authorization:
- You can use regular project-wide scopes (for example
manage_orders:project-key
). - Or use store-based scopes (for example
manage_orders:project-key:luxury-brand
). - For
inStores
, at least one of the provided Store keys must be covered by your scopes; otherwise aninsufficient_scope
error is returned.
Mutations on resources in Stores
storeKey
argument. When present, the mutation is executed in the context of that Store and fails if the targeted resource does not belong to it.mutation {
createCart(draft: { currency: "USD" }, storeKey: "luxury-brand") {
id
}
}
mutation {
updateCart(
id: "123e4567-e89b-12d3-a456-426655440000"
version: 1
actions: [{ addLineItem: { sku: "..." } }]
storeKey: "luxury-brand"
) {
id
}
}
Scopes:
- Either project-wide (for example
manage_orders:project-key
) or store-based (for examplemanage_orders:project-key:luxury-brand
).
Representations
GraphQLRequest
The query, operation name, and variables that are sent to the GraphQL API.
query ​String​ | String representation of the Source Text of the Document that is specified in the Language section of the GraphQL specification. |
operationName ​String​ | Name of the operation, if you defined several operations in query . |
variables ​ | JSON object that contains key-value pairs in which the keys are variable names and the values are variable values. |
{
"query": "query getProductByKey($productKey: String!) { product(key: $productKey) { id version }}",
"operationName": "getProductByKey",
"variables": {
"productKey": "a-product-key"
}
}
GraphQLVariablesMap
The variables that the GraphQL query uses.
// ​Any string parameter matching this regular expression​ | JSON object that contains key-value pairs in which the keys are variable names and the values are variable values. |
{
"productKey": "a-product-key"
}
GraphQLResponse
error
is present in the response only if the GraphQL query was unsuccessful.data ​Any​ | JSON object that contains the results of a GraphQL query. |
errors ​Array of GraphQLError​ | Errors that the GraphQL query returns. |
{
"data": {
"product": {
"id": "35d33405-2d39-4528-b195-fa3ab6beb927",
"version": 2
}
}
}
Query GraphQL
GraphQL uses HTTP POST requests to both query and mutate data.
Execute a GraphQL request.
view_products:{projectKey}
region String ​ | Region in which the Project is hosted. |
projectKey String ​ | key of the Project. |
application/json
application/json
curl https://api.{region}.commercetools.com/{projectKey}/graphql -i \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--header 'Content-Type: application/json' \
--data-binary @- << DATA
{
"query" : "query getProductByKey($productKey: String!) { product(key: $productKey) { id version }}",
"operationName" : "getProductByKey",
"variables" : {
"productKey" : "a-product-key"
}
}
DATA
{
"data": {
"product": {
"id": "35d33405-2d39-4528-b195-fa3ab6beb927",
"version": 2
}
}
}
Using an SDK
This code assumes you have set up your SDK as described in the get started guide of your respective SDK. You may need to modify some code if your environment differs.
async function graphQLCall() {
const q = `
query getProductByKey($productKey: String!) {
product(key: $productKey) {
id
version
}
}
`;
return await apiRoot
.graphql()
.post({
body: {
query: q,
operationName: 'getProductByKey',
variables: {
productKey: 'a-product-key',
},
},
})
.execute();
}
graphQLCall()
.then(({ body }) => {
console.log(body.data);
})
.catch(console.error);
Errors
GraphQLError
Contains an error message, the location of the code that caused the error, and other information to help you correct the error.
message ​String​ | Detailed description of the error explaining the root cause of the problem and suggesting how to correct the error. |
locations ​Array of GraphQLErrorLocation​ | Location within your query where the error occurred. |
path ​Array of Any​ | Query fields listed in order from the root of the query response up to the field in which the error occurred. path is displayed in the response only if an error is associated with a particular field in the query result. |
extensions ​ | Dictionary with additional information where applicable. |
{
"message": "Object 35d33405-2d39-4528-b195-fa3ab6beb927 has a different version than expected. Expected: 1 - Actual: 2.",
"path": [
"deleteProduct"
],
"locations": [
{
"line": 2,
"column": 3
}
],
"extensions": {
"code": "ConcurrentModification",
"currentVersion": 2
}
}
GraphQLErrorLocation
Represents the location within your query where the error occurred.
line ​Int​ | Line number of the query where the error occurred. |
column ​Int​ | Position in line where the error occurred. |
GraphQLErrorObject
Represents a single error.
code ​String​ | One of the error codes that is listed on the Errors page. |
// ​Any string parameter matching this regular expression​ | Error-specific additional fields. |
Structure GraphQL requests
The structure of GraphQL calls vary based on whether you want to query, create, update, or delete resources.
Query existing resources
query
. A name can be included to describe the call.query ReturnCustomers{}
Add an endpoint
customers
targets all Customers. To target a single Customer, use customer
.query ReturnCustomers{
customers{
}
}
query ReturnASingleCustomer {
customer() {
}
}
Add query parameters
customers
(where all Customers are targeted) these query parameters can be added based on your requirements.Parameter | Action | Example use |
---|---|---|
where | Only returns resources that match the Query Predicate. Quotation marks within quotation marks must be escaped. | where: "firstName=\"John\"" |
sort | Changes the order of the returned resources. | sort: "lastName asc" |
limit | The maximum number of results to return. The default value is 20. | limit: 5 |
offset | Used for skipping results. The default value is 0. | offset: 1 |
customer
(where a single Customer is targeted) you must enter a unique identifier for the resource (usually its id
or key
).()
next to the endpoint:query ReturnCustomers {
# Return up to five Customers named "John", ordered by their surname (ascending), and not including the first result
customers(where: "firstName=\"John\"", sort: "lastName asc", limit: 5, offset: 1) {
}
}
query ReturnASingleCustomer {
# Return a Customer based on their id
customer(id: "{customerID}") {
}
}
Choose what to return
customers
(where all Customers are targeted) you can return the following:offset
is the same value you selected in the parameters.count
is the number of resources returned based on thelimit
parameter.total
is the total number of resources in your Project.exists
returns a boolean value to indicate whether a queried resource exists.results
is the object where you include the values (such asid
orversion
) you want to be returned.
customer
(where a single Customer is targeted), you only choose the values of the resource to return.query ReturnCustomers {
# Return up to five Customers named "John", ordered by their surname (ascending), and not including the first result
customers(
where: "firstName=\"John\""
sort: "lastName asc"
limit: 5
offset: 1
) {
# Display the offset, count, and total
offset
count
total
results {
# Return the Customer's ID, version, email, and name.
id
version
email
firstName
lastName
}
}
}
query ReturnASingleCustomer {
# Return a Customer based on their id
customer(id: "{customerID}") {
id
version
email
firstName
lastName
}
}
Create and update resources
mutation
. A name can be included to describe the call.mutation CreateDiscountCode{}
mutation DeactivateDiscountCode{}
Add an action
mutation
requires an action. The chosen action determines whether you are creating a new resource or updating an existing one.When creating a new resource
You must also include the values you want GraphQL to return once the resource has been created.
mutation CreateDiscountCode {
# The action for creating a Discount Code
createDiscountCode(
# The DiscountCodeDraft and its required fields
draft: {
code: "SAVE25"
isActive: true
cartDiscounts: { typeId: "cart-discount", id: "{cartDiscountID}" }
}
) {
# The values to return
code
isActive
}
}
When updating an existing resource
Like with the HTTP API, you must post an array of update actions to modify the data of existing resources.
You must also include the values you want GraphQL to return once the resource has been updated.
mutation DeactivateDiscountCode {
# The action to update an existing resource
updateDiscountCode(
version: 1
id: "{discountCodeID}"
## Include update actions and their required parameters
actions: [{ changeIsActive: { isActive: false } }]
) {
# The values to return
code
isActive
}
}
Delete resources
mutation
. You can include a name to describe the call.mutation DeleteDiscountCode {
# The action to delete an existing resource
deleteDiscountCode(version: 1, id: "{discountCodeID}") {
# The values to return
id
code
}
}
Check if resources exist
200
or 404
status code to indicate whether a resource exists, based on an identifier or query predicate. In GraphQL, the equivalent functionality is provided by the exists
field.true
if there is at least one result matching the query condition, or false
if there are none.# Quotation marks within quotation marks must be escaped.
query checkIfResourceExistsById {
customers(where: "id=\"ba5f454f-dab5-4f95-802f-f1c285be7167\"") {
exists
}
}
query checkIfResourceExistsByKey {
customers(where: "key=\"a-customer-key\"") {
exists
}
}
query checkIfResourceExistsByQueryPredicate {
customers(where: "firstName=\"John\" and lastName=\"Smith\"") {
exists
}
}
{
"data": {
"customers": {
"exists": true
}
}
}
Reference Expansion
By convention, the GraphQL API offers two fields for each expandable reference:
<fieldName>Ref
- Fetches the Reference or KeyReference to the resource only (lower query complexity).<fieldName>
- Fetches the expanded resource that is referenced (higher query complexity).
Returnsnull
if the referenced resource is not found.
<fieldName>Ref
to get a better performance on your query.For example, to retrieve the number of child Categories for a specific Category and the identifiers for its ancestors:
{
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
children {
id
}
ancestors {
id
}
}
}
{
"data": {
"category": {
"children": [
{
"id": "7900ab4b-c01c-4e73-8f10-557b84de55f5"
},
{
"id": "93aa3372-310f-4fa7-8ab2-986036382e4f"
},
{
"id": "0938dbd3-766e-48c2-b86b-31a3a3d820da"
}
],
"ancestors": [
{
"id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
}
]
}
}
}
children
array. The identifiers for ancestors are listed in the ancestors
field.childCount
field. Also, if you only need the identifiers for the ancestors, it is better to use the ancestorsRef
field.{
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
childCount
ancestorsRef {
id
}
}
}
{
"data": {
"category": {
"childCount": 3,
"ancestorsRef": [
{
"id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
}
]
}
}
}
Custom Fields
value
of the referenced Custom Object in the same query.query {
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
custom {
customFieldsRaw(includeNames: ["categoryCustom"]) {
referencedResource {
... on CustomObject {
value
}
}
}
}
}
}
{
"data": {
"category": {
"custom": {
"customFieldsRaw": [
{
"referencedResource": {
"value": {
"extraCategoryData": "This is extra Category data"
}
}
}
]
}
}
}
}
Custom Objects BETA
referencedResources(expand: [String!]): [ReferencedResource!]
.{
"id": "687e312c-600a-4544-af21-ca1f6313bfde",
"version": 5,
...
"container": "myContainer",
"key": "myKey",
"value": {
"reviewRating": {
"typeId": "review",
"id": "d77f00e0-1cd5-0bfa-b566-bcd105d86edd"
}
}
}
The following query represents how to expand the referenced Review contained in the payload of your Custom Object.
query {
customObject(container: "myContainer", key: "myKey") {
referencedResources(expand: ["reviewRating"]) {
path
objs {
... on Review {
text
}
}
}
}
}
{
"data": {
"customObject": {
"referencedResources": [
{
"path": "reviewRating",
"objs": [
{
"text": "some review text"
}
]
}
]
}
}
}
If your Custom Object contains a list of References, like the following example containing an array of References to Review resources:
{
"id": "687e312c-600a-4544-af21-ca1f6313bfde",
"version": 7,
...
"container": "containerForReferences",
"key": "listOfReferences",
"value": {
"reviewReferences": [
{
"id": "6e46a6fc-bdee-4159-a07d-ce7b8f6f130f",
"typeId": "review"
},
{
"id": "e8f32564-7963-4c8a-906e-cdc675aba9e8",
"typeId": "review"
},
{
"id": "9902febb-6208-4322-9d7a-d622ec3e4f4f",
"typeId": "review"
}
]
}
}
text
field from the expanded Review resources:{
customObject(container: "containerForReferences", key: "listOfReferences") {
key
referencedResources(expand: "reviewReferences[*]") {
path
objs {
... on Review {
text
}
}
}
}
}
{
"data": {
"customObject": {
"key": "listOfReferences",
"referencedResources": [
{
"path": "reviewReferences[*]",
"objs": [
{
"text": "Some review text"
},
{
"text": "Another review text"
},
{
"text": "Would buy again"
}
]
}
]
}
}
}
expand: "reviewReferences[*]"
.
The expansion path syntax allows you to expand only specific elements of the array also.parent
of a referenced Category,
the expansion path expand: "category.parent"
does not work.Instead, you specify only the top level reference in the expansion path, and query for any nested references in the fragment part of the GraphQL query, like in the following example:
query {
customObject(container: "custom-object-container", key: "custom-object-key") {
referencedResources(expand: ["category"]) {
path
objs {
... on Category {
parent {
name(locale: "en")
}
}
}
}
}
}
{
"data": {
"customObject": {
"referencedResources": [
{
"path": "category",
"objs": [
{
"parent": {
"name": "some category name"
}
}
]
}
]
}
}
}
If your Custom Object value contains references of different resource types, like in the following example:
{
...
"container": "custom-object-container",
"key": "custom-object-key",
"value": [
{
"category": {
"id": "ba5704a1-77b5-4be4-bfb1-24f6a2630d82",
"typeId": "category"
}
},
{
"review": {
"id": "6e46a6fc-bdee-4159-a07d-ce7b8f6f130f",
"typeId": "review"
}
}
]
}
you can request expanding both references in the same query by providing both expansion paths:
query {
customObject(container: "custom-object-container", key: "custom-object-key") {
referencedResources(expand: ["category", "review"]) {
path
objs {
... on Category {
parent {
name(locale: "en")
}
}
... on Review {
text
}
}
}
}
}
{
"data": {
"customObject": {
"referencedResources": [
{
"path": "category",
"objs": [
{
"parent": {
"name": "root category"
}
}
]
},
{
"path": "review",
"objs": [
{
"text": "awesome test review"
}
]
}
]
}
}
}
Variant Attributes
referencedResource
(for single references) and referencedResourceSet
(for sets of references) under attributesRaw
for allVariants
or masterVariant
:{
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
allVariants {
attributesRaw {
referencedResource {
## If a referenced Product exists, return its name, SKUs, and key
... on Product {
masterData {
current {
slug(locale: "en")
}
}
skus
key
}
## If a referenced ProductType exists, return the Attributes names and ProductType name
... on ProductTypeDefinition {
attributeDefinitions {
results {
name
}
}
name
}
}
referencedResourceSet {
## If a set of referenced Products exists, return their names, SKUs, and keys
... on Product {
masterData {
current {
slug(locale: "en")
}
}
skus
key
}
## If a set of referenced ProductTypes exists, return their Attribute names and ProductType names
... on ProductTypeDefinition {
attributeDefinitions {
results {
name
}
}
name
}
}
}
}
}
}
}
}
Nested Attributes BETA
attributesRaw
field on RawProductAttribute
type to gain access to referencedResource
and referencedResourceSet
, and therefore expand any references contained within the nested attribute.You can include multiple levels of nested attributes, but doing so increases the total cost of the query.
{
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
allVariants {
attributesRaw {
name
attributesRaw {
name
referencedResource {
## If a referenced Product exists, under a nested reference, return its name, SKUs, and key
... on Product {
masterData {
current {
slug(locale: "en")
}
}
skus
key
}
}
}
}
}
}
}
}
}
Product Search Attributes
referencedResource
(for single references) and referencedResourceSet
(for sets of references) under attributesRaw
for masterVariant
.attributesRaw
field on RawProductAttribute
type to gain access to referencedResource
and referencedResourceSet
, and therefore expand any references contained within the nested attribute.{
productProjectionSearch(staged: true) {
results {
masterVariant {
attributesRaw(
includeNames: "{includedAttributes}"
excludeNames: "{excludedAttributes}"
) {
name
value
referencedResource {
id
... on Product {
skus
}
}
referencedResourceSet {
id
... on Product {
skus
}
}
}
}
}
}
}
Query complexity
You can fetch a lot of information in a single HTTP request using GraphQL. This is helpful to avoid parsing unused fields, and the unnecessary network overhead by reducing the number of requests. At the same time, it is important to remember that a single query can potentially generate a lot of database operations. Hence, you cannot assume that the response time for a query increases linear with the number of fields in the query.
The GraphQL schema defines a "cost" per field, which you can display using following options:
-
Inspecting the
x-graphql-query-complexity
response header and its value. -
Using the GraphQL Explorer query profiler to measure the impact.
QueryComplexityLimitExceeded
20 000
. In such cases, queries return a QueryComplexityLimitExceeded error code with the HTTP status code 400
.code ​String​ | "QueryComplexityLimitExceeded" |
message ​String​ | |
// ​Any string parameter matching this regular expression​ | Error-specific additional fields. |
Advanced queries
Query Attributes, Custom Objects, and Custom Fields
Attributes, Custom Objects, and Custom Fields contain Project-specific dynamic data that can be accessed by using raw GraphQL fields.
Retrieve Variant Attributes
value
field reflect the data type that is used by the Attribute. For more information, see AttributeType. You must determine the data type yourself.query {
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
variants {
...variantFields
}
}
}
}
}
fragment variantFields on ProductVariant {
sku
attributesRaw {
name
value
}
}
{
"data": {
"product": {
"masterData": {
"current": {
"variants": [
{
"sku": "M0E20000000E218",
"attributesRaw": [
{
"name": "productSupported",
"value": true
},
{
"name": "supportContact",
"value": {
"en": "english@example.com",
"de": "german@example.com"
}
}
]
}
]
}
}
}
}
}
Retrieve values of enum Attributes in a ProductType
results
field contains an array of objects containing name
and type
of all Attributes in your Project. If results[*].type.name
is enum
or lenum
, an additional values
field is present, which contains the possible values of the enum Attributes.{
productType(key: "product-type-key") {
attributeDefinitions {
results {
name
type {
name
...enumValues
...localizedEnumValues
}
}
}
}
}
fragment enumValues on EnumAttributeDefinitionType {
values {
results {
key
label
}
}
}
fragment localizedEnumValues on LocalizableEnumAttributeDefinitionType {
values {
results {
key
labelAllLocales {
locale
value
}
}
}
}
{
"data": {
"productType": {
"attributeDefinitions": {
"results": [
{
"name": "creationDate",
"type": {
"name": "datetime"
}
},
{
"name": "articleNumberManufacturer",
"type": {
"name": "text"
}
},
{
"name": "madeInItaly",
"type": {
"name": "enum",
"values": {
"results": [
{
"key": "yes",
"label": "yes"
},
{
"key": "no",
"label": "no"
}
]
}
}
},
{
"name": "color",
"type": {
"name": "lenum",
"values": {
"results": [
{
"key": "black",
"labelAllLocales": [
{
"locale": "en",
"value": "black"
},
{
"locale": "de",
"value": "schwarz"
}
]
},
{
"key": "white",
"labelAllLocales": [
{
"locale": "de",
"value": "weiss"
},
{
"locale": "en",
"value": "white"
}
]
}
]
}
}
}
]
}
}
}
}
Retrieve Custom Fields
value
field reflect the data type that is used by the Custom Field. For more information, see FieldType. You must determine the data type yourself.{
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
variants {
prices {
...customFields
}
}
}
}
}
}
fragment customFields on ProductPrice {
custom {
customFieldsRaw {
name
value
}
}
}
{
"data": {
"product": {
"masterData": {
"current": {
"variants": [
{
"prices": [
{
"custom": {
"customFieldsRaw": [
{
"name": "kiloPrice",
"value": {
"type": "centPrecision",
"currencyCode": "EUR",
"centAmount": 95,
"fractionDigits": 2
}
}
]
}
}
]
}
]
}
}
}
}
}
Create Attributes, Custom Fields, and Custom Objects
value
field should be a string containing escaped JSON.value
field on ProductAttributeInput
:"{\"type\": \"centPrecision\", \"currencyCode\": \"USD\", \"centAmount\": 1000, \"fractionDigits\": 2}"
"\"yellow\""
value
field on CustomFieldInput
:"[\"This is a string\", \"This is another string\"]"
"{\"id\": \"b911b62d-353a-4388-93ee-8d488d9af962\", \"typeId\": \"product\"}"
value
field on CustomObjectDraft
:"{ \"stringField\": \"myVal\", \"numberField\": 123, \"boolField\": false, \"nestedObject\": { \"nestedObjectKey\": \"anotherValue\" }, \"dateField\": \"2018-10-12T14:00:00.000Z\" }"
Use Search queries
You can implement storefront search applications using the GraphQL API.
Use Product Search BETA
productsSearch
query.Example
query ProductSearchExample {
productsSearch(
query: {
and: [
{ exact: { field: "variants.prices.currencyCode", value: "USD" } }
{ exists: { field: "variants.prices.centAmount" } }
{ exists: { field: "name", language: "en" } }
{
fullText: {
field: "description"
value: "Sample Product"
language: "en"
}
}
{ range: { long: { field: "variants.prices.centAmount", lte: 15 } } }
{
range: {
datetime: { field: "createdAt", gte: "2024-01-01T00:00:00" }
}
}
{
or: [
{ exact: { field: "name", value: "Club Mate", language: "en" } }
{ exact: { field: "name", value: "Spezi", language: "en" } }
{ exact: { field: "name", value: "Cola", language: "en" } }
]
}
]
}
postFilter: {
and: [
{ exact: { field: "variants.prices.currencyCode", value: "USD" } }
{ exists: { field: "variants.prices.centAmount" } }
]
}
sort: [{ field: "name", order: asc, language: "en" }]
limit: 10
offset: 0
markMatchingVariants: true
facets: [{ distinct: { name: "productKeys", field: "key", limit: 10 } }]
) {
total
offset
limit
results {
id
product {
id
}
}
facets {
name
}
}
}
query
argument follows the SearchQuery documentation.productProjectionsSearch
where the product fields are directly selectable on the results, there is a dedicated product
sub field in results
.Fetch all Product Variants
productsSearch
query provides the following query fields to fetch the Master Variant or the additional Product Variants of a Product Projection separately or all together.masterData
- Fetches the selected (current, staged) master data.variants
- Fetches only the additional Product Variants.allVariants
- Fetches all Product Variants including the Master Variant.
query Products {
productsSearch(
query: {
fullText: { field: "description", value: "pants", language: "en" }
}
) {
total
results {
product {
key
masterData {
current {
name(locale: "en")
variants {
sku
}
allVariants {
sku
}
}
}
}
}
}
}
productsSearch
query also supports markMatchingVariants
, see the explanations in Product Projections Search.Use Product Projection Search
- via API using the Change Product Search Indexing Enabled update action on the Project endpoint.
- via the Merchant Center by navigating to Settings > Project settings > Storefront Search.
- via contacting the Composable Commerce support team and provide your region, Project key, and use case.
Search based on text and locale
query {
productProjectionSearch(staged: true, locale: "en-US", text: "bed") {
total
# Uncomment to return the ID and English name of each result.
# results{
# id
# name(locale:"en-US")
# }
}
}
{
"data": {
"productProjectionSearch": {
"total": 17
}
}
}
Search based on text, locale, and filtering
query {
productProjectionSearch(
queryFilters: [{ string: "published:true" }]
staged: true
locale: "en-US"
text: "bed"
) {
# Return the total number of results.
total
# Uncomment to return the ID and English name of each result.
# results{
# id
# name(locale:"en-US")
# }
}
}
{
"data": {
"productProjectionSearch": {
"total": 17
}
}
}
Search using filters
query {
productProjectionSearch(
staged: true
filters: [
{
model: {
value: { path: "variants.price.centAmount", values: ["1599"] }
}
}
]
) {
total
results {
id
version
}
}
}
{
"data": {
"productProjectionSearch": {
"total": 3,
"results": [
{
"id": "394f20b4-0b21-45f7-81cc-43a4e45ba775",
"version": 1
},
{
"id": "ecc60e5f-ddd7-4137-8b84-fcaa17426549",
"version": 3
},
{
"id": "df65a374-e281-41a1-a370-c4d2591cae39",
"version": 1
}
]
}
}
}
Retrieve facet calculation
query {
productProjectionSearch(
facets: [
{
model: {
range: {
path: "variants.price.centAmount"
ranges: [{ from: "1000", to: "3000" }]
countProducts: false
}
}
}
]
) {
facets {
facet
value {
type
... on RangeFacetResult {
dataType
ranges {
type
... on RangeCountDouble {
from
fromStr
to
toStr
count
productCount
totalCount
total
min
max
mean
}
}
}
}
}
}
}
{
"data": {
"productProjectionSearch": {
"facets": [
{
"facet": "variants.price.centAmount",
"value": {
"type": "range",
"dataType": "number",
"ranges": [
{
"type": "double",
"from": 1000,
"fromStr": "1000.0",
"to": 3000,
"toStr": "3000.0",
"count": 35,
"productCount": null,
"totalCount": 35,
"total": 62065,
"min": 1099,
"max": 2999,
"mean": 1773.2857142857142
}
]
}
}
]
}
}
}
Differentiate between highPrecision and centPrecision money
{
productProjectionSearch(staged: false, locale: "en", text: "blue") {
count
results {
id
masterVariant {
sku
prices {
...productPrice
}
}
}
}
}
fragment productPrice on ProductPriceSearch {
value {
...money
__typename
}
discounted {
value {
...money
__typename
}
__typename
}
}
fragment money on BaseMoney {
type
currencyCode
centAmount
fractionDigits
... on HighPrecisionMoney {
preciseAmount
}
}
{
"data": {
"productProjectionSearch": {
"results": [
{
"id": "500797c7-e719-4d72-8c69-92fdee39d451",
"masterVariant": {
"sku": "M0E20000000E582",
"prices": [
{
"value": {
"type": "highPrecision",
"currencyCode": "USD",
"centAmount": 24875,
"fractionDigits": 11,
"preciseAmount": 24875123456789,
"__typename": "HighPrecisionMoney"
},
"discounted": null
},
{
"value": {
"type": "centPrecision",
"currencyCode": "EUR",
"centAmount": 16311,
"fractionDigits": 2,
"__typename": "Money"
},
"discounted": null
}
]
}
}
]
}
}
}
Fetch all Product Variants
productProjectionSearch
query provides the following query fields to fetch the Master Variant or the additional Product Variants of a Product Projection separately or all together.masterVariant
- Fetches the Master Variant only.variants
- Fetches only the Product Variants in addition to the Master Variant.allVariants
- Fetches all Product Variants including the Master Variant.
query {
productProjectionSearch {
results {
masterVariant {
key
}
variants {
id
}
allVariants {
sku
}
}
}
}
Fetch only matching Product Variants
productProjectionSearch
query, you can control whether or not the response contains only the Product Variants that match the search query.
To accomplish this, set markMatchingVariants: true
, and set the onlyMatching
flag in the variants
or allVariants
field to true
.The flag behaves as follows:
onlyMatching: true
- Returns only the matching Product Variants.onlyMatching: false
- Returns only the non-matching Product Variants.- no flag - Returns all Product Variants.
onlyMatching
flag without setting markMatchingVariants
to true
, the results will be empty even though matching Product Variants may exist.query {
productProjectionSearch(
markMatchingVariants: true
queryFilters: {
model: { value: { path: "variants.price.centAmount", values: ["1299"] } }
}
) {
results {
key
allVariants(onlyMatching: true) {
sku
}
}
count
}
}
Use Search Term Suggestions
productProjectionsSuggest
query.query {
productProjectionsSuggest(
searchKeywords: { searchKeyword: "swiss", locale: "en" }
) {
searchKeywords {
suggestions {
text
}
}
}
}
{
"data": {
"productProjectionsSuggest": {
"searchKeywords": [
{
"suggestions": [
{
"text": "Swiss Army Knife"
}
]
}
]
}
}
}
Public beta functionalities BETA
createdBy
andlastModifiedBy
onVersioned
MultiBuyLineItemsTarget
andMultiBuyCustomLineItemsTarget
onCartDiscount
stores
onCartDiscount
NestedTypes
onProductType
attributesRaw
onRawProductAttribute
,productsSearch
query,- everything related to
MyCart
,MyOrder
,MyPayment
,MyProfile
,MyShoppingList
,MyBusinessUnit
,MyQuote
,MyQuoteRequest