Skip to content

Get Attributes

About

The attributes query returns a cursor-paginated list of every product attribute in the catalog, each with its configuration, its selectable options, and its per-locale names. Use it to:

  • Discover which attributes exist and which of them are filterable or configurable
  • Cache an attribute-code to option-ID map that a client reuses across screens
  • Read swatch settings before rendering colour or image pickers
  • Read attribute and option labels in every locale a store supports

The list is not category-aware. To build a filter sidebar for one category, use Category Attribute Filters, which returns only the attributes that belong on that category. To read a single attribute, use Get Attribute.

Arguments

ArgumentTypeRequiredDescription
firstInt❌ NoNumber of attributes to return from the start (forward pagination). Default: 10
afterString❌ NoCursor to start after for forward pagination. Take it from the previous response's endCursor.
lastInt❌ NoNumber of attributes to return from the end (backward pagination). Default: 10
beforeString❌ NoCursor to start before for backward pagination.

There is no argument to filter the list — by code, by type, or by the filterable flag. Fetch the page and narrow it in the client, or use the category-scoped query instead.

Possible Returns

FieldTypeDescription
edges[AttributeEdge]Attribute edges for the current page.
edges.nodeAttributeA single attribute — fields below.
edges.cursorString!Cursor for this attribute, used as after on the next request.
pageInfoAttributePageInfo!Pagination metadata.
pageInfo.hasNextPageBooleanWhether more attributes follow the current page.
pageInfo.hasPreviousPageBooleanWhether attributes precede the current page.
pageInfo.startCursorStringCursor of the first attribute on the page.
pageInfo.endCursorStringCursor of the last attribute on the page.
totalCountInt!Total attributes in the catalog.

Attribute Fields

The is* and valuePer* flags come back as the strings "1" / "0", not as GraphQL booleans.

FieldTypeDescription
idID!IRI-style identifier (/api/shop/attributes/23).
_idInt!Numeric attribute ID.
codeString!Machine-readable code — sku, color, size. This is the key a product filter expects.
adminNameString!Admin-facing name. Use translation for the shopper-facing label.
typeString!Input type — see Attribute Types.
swatchTypeStringSwatch style for this attribute's options, or null when it uses none.
positionIntSort order among attributes.
isRequiredString!"1" when the attribute is mandatory on the product form.
isUniqueString!"1" when values must be unique across products.
isFilterableString!"1" when the attribute can drive layered navigation.
isComparableString!"1" when the attribute appears on the compare page.
isConfigurableString!"1" when the attribute can define configurable-product variants.
isUserDefinedString!"1" for a merchant-created attribute, "0" for a system one.
isVisibleOnFrontString!"1" when the attribute is shown on the product page.
valuePerLocaleString!"1" when the value differs per locale.
valuePerChannelString!"1" when the value differs per channel.
defaultValueIntDefault option ID, when the attribute defines one.
validationStringValidation rule applied to the value, e.g. decimal. null when none is set.
validationsStringAdditional validation metadata as a string, e.g. { required: true }.
regexStringRegular expression the value must match, when configured.
columnNameStringUnderlying storage column, when applicable.
enableWysiwygString!"1" when the admin editor uses a rich-text field.
createdAtStringISO 8601 creation timestamp.
updatedAtStringISO 8601 timestamp of the last change.
optionsAttributeOptionCursorConnectionSelectable values. Empty for text, textarea, price, date, and boolean attributes.
translationAttributeTranslationThe attribute's name in the current locale.
translationsAttributeTranslationCursorConnectionThe attribute's name in every locale.

Option Fields

Each node in an attribute's options connection:

FieldTypeDescription
idID!IRI-style option identifier.
_idInt!Numeric option ID. This is the value to send when filtering products.
adminNameStringAdmin-facing option name. Use translation for the shopper-facing label.
sortOrderIntDisplay order within the attribute.
swatchValueStringHex colour for a colour swatch, or the text value.
swatchValueUrlStringURL of the swatch image, for image swatches.
translationAttributeOptionTranslationThe option's label in the current locale.
translationsAttributeOptionTranslationCursorConnectionThe option's label in every locale.

Translation Fields

FieldTypeDescription
idID!IRI-style translation identifier.
_idInt!Numeric translation ID.
localeString!Locale code, e.g. en, ar.
attributeIdString!Parent attribute ID, on an attribute translation.
attributeOptionIdString!Parent option ID, on an option translation.
nameStringAttribute name in that locale.
labelStringOption label in that locale.

Attribute Types

TypeControlCarries options
textSingle-line text inputNo
textareaMulti-line text, optionally rich-text when enableWysiwyg is "1"No
selectDropdown, one valueYes
multiselectMultiple valuesYes
checkboxMultiple values as checkboxesYes
booleanYes/No toggleNo
date / datetimeDate pickerNo
priceDecimal amountNo
image / fileUploaded assetNo

Only the option-carrying types return anything in their options connection; the rest come back empty.

Use Cases

1. Discovering the filterable attributes

There is no filter argument, so page the list and select the ones flagged filterable in the client:

graphql
query filterableAttributes {
  attributes(first: 100) {
    edges {
      node {
        _id
        code
        adminName
        type
        swatchType
        isFilterable
        translation {
          name
        }
      }
    }
    totalCount
  }
}

Keep the nodes whose isFilterable equals the string "1".

2. Caching an option-ID to label map

Attribute values on a product come back as option IDs. Fetch the attributes with their options once and cache the mapping, rather than resolving labels product by product:

graphql
query attributeOptionMap {
  attributes(first: 100) {
    edges {
      node {
        code
        options(first: 100) {
          edges {
            node {
              _id
              translation {
                label
              }
            }
          }
        }
      }
    }
  }
}

3. Paging through the full list

graphql
query nextAttributes($after: String) {
  attributes(first: 10, after: $after) {
    edges {
      node {
        _id
        code
        adminName
      }
      cursor
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Repeat with the returned endCursor while hasNextPage is true.

Best Practices

  1. Request a large first when caching — the default page is 10 attributes, and a client that wants the whole set otherwise pays several round trips
  2. Compare the flags against stringsisFilterable and its siblings return "1" / "0", so testing the raw string for truthiness treats "0" as true
  3. Page the nested options connection too — it is a connection in its own right with its own default of 10, so a brand attribute with hundreds of values is silently truncated
  4. Select only the locales you need — asking for translations on both the attribute and every option multiplies the response, while translation returns just the current locale
  5. Use the category-scoped query for a filter sidebarCategory Attribute Filters returns only what belongs on that category, with the price range attached
  6. Never pass a made-up cursor — an after value that did not come from a previous response fails the request rather than returning an empty page

Error Scenarios

ScenarioCause
Invalid cursorThe after or before value is not a cursor returned by a previous response.

Released under the MIT License.