Product Search

Elevate, May 20-22-2025, Miami Beach, Florida

Product Search enables you to create storefront discovery experiences for your customers where they can browse and search across your Products.

  • After completing this page, you should be able to:

    • Explain the main differences between Product Search and other product-related endpoints
    • Enable Product Search in your project
    • Create basic Product Search queries
    • Use compound expressions in your Product Search queries
  • Time to complete page: 25 minutes

    Good product search capability is not just a technical necessity but a strategic asset that directly impacts customer satisfaction, conversion rates, and overall business success in a digital commerce environment. You should be familiar with a range of product-related endpoints that can help us manage products (/products), view specific product projections (/product-projections) and search for products along with performing a price selection (/product-projections/search). These allow us to achieve a lot, but what if we want to search products only belonging to a specific product selection? Or if we want to control which products from our search results should appear before other ones? The Product Search endpoint can help us achieve that.

    The new Product Search endpoint is designed to deliver more precise, personalized, and faster results by offering users greater flexibility and control over their search queries, which are now provided in the request body. Unlike the older Product Projection Search, this endpoint enables searching across Stores, Product Selections, and Standalone Prices, ensuring a more tailored and efficient search experience. But let’s not get ahead of ourselves! To use this endpoint we need to first enable it in our project. This currently can only be done via the API by submitting an update request to your Project endpoint containing the changeProductIndexingEnabled Update Action:

    Activate Product Search endpoint
    // Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example.
    
    System.out.println(
      "Product Search indexing status: " +
      apiRoot
        .post(
          ProjectUpdateBuilder
            .of()
            .version(project.getVersion())
            .actions(
              ProjectChangeProductSearchIndexingEnabledActionBuilder
                .of()
                .enabled(true)
                .build()
            )
            .build()
        )
        .executeBlocking()
        .getBody()
        .getSearchIndexing()
        .getProductsSearch()
        .getStatus()
    );
    apiRoot.close();
    

    It’s worth pointing out that once activated, Product Search will deactivate itself if the feature is not used for the duration of 30 consecutive days. Once Product Search is activated (and we give it a bit of time to index all of our Products) we can write our first Product Search Request:

    Create a Product Search Request
    // Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example.
    
    // Build search request
    var searchRequest = ProductSearchRequestBuilder
      .of()
      .query(
        SearchFullTextExpressionBuilder
          .of()
          .fullText(
            SearchFullTextValueBuilder
              .of()
              .value("Cocktail")
              .field("name")
              .language("en-GB")
              .mustMatch(SearchMatchType.ANY)
              .build()
          )
          .build()
      )
      // If productProjectionSearchParameters are not specified, only Product ID's will be returned
      .productProjectionParameters(
        ProductSearchProjectionParamsBuilder.of().staged(false).build()
      )
      .build();
    
    // Perform product search
    ProductPagedSearchResponse searchResponse = apiRoot
      .products()
      .search()
      .post(searchRequest)
      .executeBlocking()
      .getBody();
    
    // Close API client
    apiRoot.close();
    
    System.out.println("Found Products:");
    // Print all product names in English
    searchResponse
      .getResults()
      .forEach(product ->
        System.out.println(product.getProductProjection().getName().get("en-GB"))
      );
    

    From the results we can see that the result contains a list of Products which have the word “Cocktail” in their en-GB name:

    Found Products:
    Cocktail Strainer
    Cocktail Shaker
    Cocktail Shaker Set
    Cocktail Stirring Spoon
    

    If you think that we could do this previously using the /product-projections/search endpoint, you would be almost right about that, but we are just getting started. Notice that in Product Search the query is posted in the body of the request. This means that we have a lot more flexibility when it comes to shaping our query. In our basic example above we are making a fullText search, but Product Search also supports other query expressions, such as exact, prefix, range, wildcard and exists. Not only that, but these expressions can also be compounded!

    With this knowledge, let’s update our example and search for a Product where the en-GB name starts with the word “Cotton” and has either “King” or “Queen” size:

    Search for a product with certain criteria
    // Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example.
    
    var searchRequest = ProductSearchRequestBuilder
      .of()
      .query(
        SearchAndExpressionBuilder
          .of()
          .and(
            SearchPrefixExpressionBuilder
              .of()
              .prefix(
                SearchAnyValueBuilder
                  .of()
                  .value("Cotton")
                  .language("en-GB")
                  .field("name")
                  .build()
              )
              .build()
          )
          .plusAnd(
            SearchOrExpressionBuilder
              .of()
              .or(
                SearchExactExpressionBuilder
                  .of()
                  .exact(
                    SearchAnyValueBuilder
                      .of()
                      .value("King")
                      .language("en-GB")
                      .field("variants.attributes.size")
                      .fieldType(SearchFieldType.LTEXT)
                      .build()
                  )
                  .build()
              )
              .plusOr(
                SearchExactExpressionBuilder
                  .of()
                  .exact(
                    SearchAnyValueBuilder
                      .of()
                      .value("Queen")
                      .language("en-GB")
                      .field("variants.attributes.size")
                      .fieldType(SearchFieldType.LTEXT)
                      .build()
                  )
                  .build()
              )
              .build()
          )
          .build()
      )
      .productProjectionParameters(
        ProductSearchProjectionParamsBuilder.of().staged(false).build()
      )
      .markMatchingVariants(true)
      .build();
    
    // Perform product search
    ProductPagedSearchResponse searchResponse = apiRoot
      .products()
      .search()
      .post(searchRequest)
      .executeBlocking()
      .getBody();
    
    // Close API client
    apiRoot.close();
    
    System.out.println("Found Products:");
    // Print all product names in English
    searchResponse
      .getResults()
      .forEach(product -> {
        System.out.println(
          product.getProductProjection().getName().get("en-GB") +
          "\nMatching variants:"
        );
        product
          .getMatchingVariants()
          .getMatchedVariants()
          .forEach(variant -> System.out.println("SKU: " + variant.getSku()));
      });
    

    As you can see in the results, several SKUs of the Cotton Silk Bedsheet meet our search criteria:

    Found Products:
    Cotton Silk Bedsheet
    Matching variants:
    SKU: CSKW-093
    SKU: CSKW-9822
    SKU: CSKP-0932
    SKU: CSKP-083
    SKU: CSKG-023
    SKU: CSKG-2345
    

    Product Search is not just powerful; it’s incredibly versatile! The examples we’ve explored merely scratch the surface of its potential. You can enhance your results through boosting and sorting, apply filters and facets for precise searches, and even implement price selection to fit the search results to your needs:

    A search example combining boosting, sorting, filters, facets, and price selection
    // Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example.
    
    // Build the search request
    var searchRequest = ProductSearchRequestBuilder
      .of()
      .query(
        SearchAndExpressionBuilder
          .of()
          .and(
            SearchFilterExpressionBuilder
              .of()
              .filter(
                SearchExistsExpressionBuilder
                  .of()
                  .exists(
                    SearchExistsValueBuilder
                      .of()
                      .field("variants.availability")
                      .build()
                  )
                  .build()
              )
              .build()
          )
          .plusAnd(
            SearchOrExpressionBuilder
              .of()
              .or(
                SearchFullTextExpressionBuilder
                  .of()
                  .fullText(
                    SearchFullTextValueBuilder
                      .of()
                      .value("Modern")
                      .language("en-US")
                      .field("name")
                      .boost(2.0)
                      .build()
                  )
                  .build()
              )
              .plusOr(
                SearchFullTextExpressionBuilder
                  .of()
                  .fullText(
                    SearchFullTextValueBuilder
                      .of()
                      .value("Rustic")
                      .language("en-US")
                      .field("name")
                      .build()
                  )
                  .build()
              )
              .build()
          )
          .build()
      )
      .facets(
        ProductSearchFacetRangesExpressionBuilder
          .of()
          .ranges(
            ProductSearchFacetRangesValueBuilder
              .of()
              .name("Availability")
              .field("variants.availability.availableQuantity")
              .ranges(
                ProductSearchFacetRangesFacetRangeBuilder
                  .of()
                  .key("almost_out")
                  .to(10)
                  .build()
              )
              .plusRanges(
                ProductSearchFacetRangesFacetRangeBuilder
                  .of()
                  .key("limited")
                  .from(10)
                  .to(100)
                  .build()
              )
              .plusRanges(
                ProductSearchFacetRangesFacetRangeBuilder
                  .of()
                  .key("available")
                  .from(100)
                  .build()
              )
              .build()
          )
          .build()
      )
      .productProjectionParameters(
        ProductSearchProjectionParamsBuilder
          .of()
          .staged(false)
          .priceCurrency("USD")
          .priceCountry("US")
          .build()
      )
      .sort(
        SearchSortingBuilder
          .of()
          .field("name")
          .language("en-US")
          .order(SearchSortOrder.ASC)
          .build()
      )
      .build();
    
    // Execute the search request
    ProductPagedSearchResponse searchResponse = apiRoot
      .products()
      .search()
      .post(searchRequest)
      .executeBlocking()
      .getBody();
    
    apiRoot.close();
    
    // Display results
    System.out.println("Found Products:");
    searchResponse
      .getResults()
      .forEach(product -> {
        var productProjection = product.getProductProjection();
        System.out.println("Product: " + productProjection.getName().get("en-US"));
        System.out.println(
          "Master Variant: " +
          productProjection.getMasterVariant().getSku() +
          " | Price: " +
          productProjection.getMasterVariant().getPrice().getValue().getCentAmount()
        );
        productProjection
          .getVariants()
          .forEach(variant ->
            System.out.println(
              "Variant: " +
              variant.getSku() +
              " | Price: " +
              variant.getPrice().getValue().getCentAmount()
            )
          );
      });
    
    searchResponse
      .getFacets()
      .forEach(facet -> {
        try {
          System.out.println(
            "Facet results:\n" +
            JsonUtils.prettyPrint(JsonUtils.toJsonString(facet))
          );
        } catch (JsonProcessingException e) {
          throw new RuntimeException(e);
        }
      });
    

    In this example, we search for products with either “Modern” (boosted) or “Rustic” in their English names, filtering for those with specified inventory. How much inventory? The range facet provides this information, while the Price Selection reveals the cost for American customers. Finally, we sort the results alphabetically by their English names:

    RESULT:

    Found Products:
    
    Product: Minimalist Modern Side Table
    Master Variant: MMST-01 | Price: 12000
    Variant: MMST-02 | Price: 4999
    
    Product: Modern Black Coaster
    Master Variant: BCOAS-08 | Price: 1999
    
    Product: Modern Bookcase
    Master Variant: MB-0973 | Price: 29900
    
    Product: Modern Ceramic Plate
    Master Variant: MCP-01 | Price: 299
    
    Product: Modern Glam Dresser
    Master Variant: MGD-01 | Price: 179900
    
    Product: Modern Gold Coffee Table
    Master Variant: GMCT-01 | Price: 25999
    
    Product: Modern Landscape Painting
    Master Variant: MLP-01 | Price: 5299
    
    Product: Modern Three Seater Sofa
    Master Variant: MTSS-01 | Price: 249900
    
    Product: Modern Upholstered Queen Bed
    Master Variant: MUQB-01 | Price: 259900
    
    Product: Red Modern Painting
    Master Variant: RMP-01 | Price: 3299
    
    Product: Rustic Bowl
    Master Variant: RB-01 | Price: 199
    
    Product: Rustic Country Dresser
    Master Variant: RCD-01 | Price: 159900
    
    Product: Rustic Country Queen Bed
    Master Variant: RCQB-01 | Price: 329900
    
    Product: Rustic Oven Casserole
    Master Variant: RCC-09 | Price: 2599
    
    Facet Results:
    Facet: 0
    {
      "name": "Availability",
      "buckets": [
        {
          "key": "almost_out",
          "count": 1
        },
        {
          "key": "limited",
          "count": 8
        },
        {
          "key": "available",
          "count": 5
        }
      ]
    }
    

    The possibilities with Product Search are vast and exciting—dive in and discover all that it has to offer!

    Test your knowledge