For paginating the catalog, we use the GraphQL Cursor Connections Specification, which is thoroughly documented in the official guidelines.

Why Use This Approach?

Using cursor-based pagination offers several advantages:
  • Efficient Data Handling: Cursors are more efficient than offset-based pagination, especially with large or frequently updated datasets.
  • Consistency: It avoids issues with data shifting between requests (e.g., when new trainings are added or removed), ensuring stable navigation through paginated results.
  • Scalability: Better performance on large datasets, as it avoids skipping records and leverages indexed fields.
  • Built-in Navigation: The specification provides standard ways to handle forward and backward navigation (e.g., hasNextPage, endCursor), simplifying client-side implementation.
The getCatalogData query includes a pageInfo field, which provides metadata about the current result set and allows clients to effectively implement pagination.
"pageInfo": {
  "hasNextPage": true,
  "startCursor": "TzozMzoiRHJ1cGFsXG9waWdub19hcGlcV3JhcHBlcnNcQ3Vyc29yIjo0OntzOjE0OiIAKgBiYWNraW5nVHlwZSI7czo5OiJvcGlnbm9fbHAiO3M6MTI6IgAqAGJhY2tpbmdJZCI7aTo0MDtzOjEwOiIAKgBzb3J0S2V5IjtzOjU6IlRJVExFIjtzOjEyOiIAKgBzb3J0VmFsdWUiO3M6NDU6IkhvdyB0byBidWlsZCBIaWdoLUxvYWQgSW5mcmFzdHJ1Y3R1cmUgaW4gMjAyNSI7fQ==",
  "endCursor": "TzozMzoiRHJ1cGFsXG9waWdub19hcGlcV3JhcHBlcnNcQ3Vyc29yIjo0OntzOjE0OiIAKgBiYWNraW5nVHlwZSI7czo5OiJvcGlnbm9fbHAiO3M6MTI6IgAqAGJhY2tpbmdJZCI7aTozOTtzOjEwOiIAKgBzb3J0S2V5IjtzOjU6IlRJVExFIjtzOjEyOiIAKgBzb3J0VmFsdWUiO3M6MTc6IkxvY2tlZCBUcmFpbmluZyAxIjt9"
},

Fields:

  • hasNextPage (Boolean)
    Indicates whether there are more results available after the current page.
    • true → Additional pages exist.
    • false → You’ve reached the end of the list.
  • startCursor (String)
    A cursor string representing the first item in the current page. It can be used as the before parameter to fetch the previous page, if needed.
  • endCursor (String)
    A cursor string representing the last item in the current page. This value should be used as the after parameter when querying the next page of results.
Note: The cursor values (such as the encoded strings shown above) are opaque and should not be parsed or modified by clients—they are meant to be passed back to the API exactly as received.

Utilizing pageInfo in the getCatalogData Query

Building on the explanation of the pageInfo fields—hasNextPage, startCursor, and endCursor—these values can now be applied in the getCatalogData query to control pagination behavior. By using the endCursor as the after argument, clients can request the next page of results. Similarly, the startCursor can be passed as the before argument to retrieve the previous page. This approach enables efficient, cursor-based pagination that ensures consistent data retrieval, even in dynamic datasets. Please see the full list of available pagination arguments for the getCatalogData query:
ArgumentTypeDescription
afterCursorReturns the elements after the specified cursor. Use for forward pagination.
beforeCursorReturns the elements before the specified cursor. Use for backward pagination.
firstIntLimits the result to the first n elements after the after cursor.
lastIntLimits the result to the last n elements before the before cursor.

⚖️ Pagination Input Validation

The getCatalogData query supports two mutually exclusive pagination approaches. In both cases, the number of items returned must not exceed the limit of 100.
Pagination TypeRequired Argument(s)Optional CursorConstraints
Forwardfirstafterfirst must be > 0 and ≤ 100
Backwardlastbeforelast must be > 0 and ≤ 100
❌ The following combinations are not allowed:
  • Providing both first and last
  • Using first with before
  • Using last with after
  • Providing values ≤ 0 or > 100 for first or last

🔁 Loading the Next Page

To load the next set of catalog items, pass the endCursor value from the pageInfo object of the previous result into the after argument.
query getCatalogData {
  getCatalogData(first: 3, after: "TzozMzoiRHJ1cGFsXG9waWdub19hcGlcV3JhcHBlcnNcQ3Vyc29yIjo0OntzOjE0OiIAKgBiYWNraW5nVHlwZSI7czo5OiJvcGlnbm9fbHAiO3M6MTI6IgAqAGJhY2tpbmdJZCI7aTozOTtzOjEwOiIAKgBzb3J0S2V5IjtzOjU6IlRJVExFIjtzOjEyOiIAKgBzb3J0VmFsdWUiO3M6MTc6IkxvY2tlZCBUcmFpbmluZyAxIjt9") {
    edges {
      node {
        cta {
          actionId
          title
          arguments {
            key
            value
          }
          metadata {
            key
            value
          }
        }
        modulesNumber
        activitiesNumber
        training {
          title
          domain {
            name
          }
          image {
            alt
            title
            url
          }
          duration {
            name
          }
          attempt {
            metrics {
              progress
              status
            }
          }
        }
      }
    }
    pageInfo {
      hasNextPage
      startCursor
      endCursor
    }
    totalItems
  }
}
In case you reach the end of the catalog, the pageInfo.hasNextPage field will be set to false