Search Using Swift SDK

The Experience Search API is a native, AI-powered, multi-modal search solution that enables personalized search experiences on your website or app. It supports:

  • Semantic Search: Understands natural language text queries, enabling you to deliver highly relevant search results that meet user expectations and drive conversions.
  • Visual Search: Enables users to search using images from their camera or gallery to find visually similar or relevant products.
📘

For more information see the following:

Semantic Search

Parameters

ParameterData Structure TypeMandatory?Description
pagePageYesInformation about the current page (screen name, referrer, categories)
textStringYesThe natural‑language query to process using Semantic Search
filters[Filter]?NoOptional attribute filters (brand, color, price range, and so on)
paginationPaginationYesDefines number of items and offset for pagination
sortBySortOptions?NoSorting rules (for example, by field or by relevance)
pageAttributes[String: PageAttribute]?NoKey–value attributes for campaign targeting or search context
enableSpellCheckBooleanNoEnables spellcheck for the current Semantic Search request.
Disabled by default
branchIdString?NoBranch identifier for multi‑branch setups (stores, financial institutions, restaurants)
optionsSearchOptions?NoAdditional search configurations (for example, return analytics metadata)

Code example

func semanticSearch() async { 
    let result = await DYSdk.shared().search.semanticSearch() 

    switch result.status { 
    case .success, .warning: 
        guard 
            let choice = result.choice, 
            let variation = choice.variations.first 
        else { 
            print("SemanticSearch: No choice or variation returned for semantic search result") 
            return 
        } 

        let data = variation.payload.data 
        let spellCheckedQuery = data.spellCheckedQuery 
        let totalNumResults = data.totalNumResults 
        let custom = data.custom 

        print( 
            """ 
            SemanticSearch: 
              spellCheckedQuery=\(String(describing: spellCheckedQuery)) 
              totalNumResults=\(String(describing: totalNumResults)) 
              custom=\(String(describing: custom)) 
            """ 
        ) 

        // MARK: - Product Slots 
        data.slots?.forEach { slot in 
            let slotId = slot.slotId 
            let sku = slot.sku 
            print("SemanticSearch: slotId=\(String(describing: slotId)), sku=\(String(describing: sku))") 

            guard let product = slot.productData as? DefaultRecsProductData else { 
                print("SemanticSearch: productData is not DefaultRecsProductData for slot \(String(describing: slotId))") 
                return 
            } 

            let groupId = product.groupId 
            let name = product.name 
            let url = product.url 
            let price = product.price 
            let inStock = product.inStock 
            let imageUrl = product.imageUrl 
            let categories = product.categories 
            let keywords = product.keywords 

            print( 
                """ 
                SemanticSearch product: 
                  groupId=\(String(describing: groupId)), 
                  name=\(String(describing: name)), 
                  price=\(String(describing: price)), 
                  inStock=\(String(describing: inStock)), 
                  url=\(String(describing: url)) 
                """ 
            ) 

            print( 
                """ 
                SemanticSearch product details: 
                  imageUrl=\(String(describing: imageUrl)), 
                  categories=\(String(describing: categories)), 
                  keywords=\(String(describing: keywords)) 
                """ 
            ) 
        } 

        // MARK: - Facets 
        data.facets?.forEach { facet in 
            let column = facet.column 
            let displayName = facet.displayName 
            let valuesType = facet.valuesType 

            print( 
                """ 
                SemanticSearch facet: 
                  column=\(column), 
                  displayName=\(String(describing: displayName)), 
                  valuesType=\(valuesType) 
                """ 
            ) 

            if let numberFacet = facet as? NumberFacet { 
                let min = numberFacet.min 
                let max = numberFacet.max 
                print("SemanticSearch number facet: min=\(String(describing: min)), max=\(String(describing: max))") 

            } else if let stringFacet = facet as? StringFacet { 
                stringFacet.values.forEach { value in 
                    let name = value.name 
                    let count = value.count 
                    print("SemanticSearch string facet: name=\(name), count=\(count)") 
                } 
            } 
        } 

        // MARK: - Warnings 
        if result.status == .warning, let warnings = result.warnings { 
            warnings.forEach { print("SemanticSearch warning: \($0)") } 
        } 

    case .error: 
        if let error = result.error { 
            print("SemanticSearch error: \(error)") 

        } else { 
            print("SemanticSearch error: unknown error") 
        } 
    } 
} 

Spellcheck response fields

When spellcheck is enabled, the Semantic Search response can include the following:

FieldTypeDescription
searchQueryStringThe original query sent by the application
spellCheckQueryString?The corrected query (returned when a spelling correction is applied)
normalizedQueryStringThe normalized query used internally by the search engine

Notes:

  • If no correction is needed, spellCheckedQuery is either null or equal to searchQuery.
  • Spellcheck must be explicitly enabled on each Semantic Search request.

Spellcheck code sample:

func semanticSearch() async { 
    let result = await DYSdk.shared().search.semanticSearch( 
        page: Page.homePage(pageLocation: "location"), 
        text: "jeens", // typo 
        pagination: Pagination(numItems: 10, offset: 0), 
        enableSpellCheck: true 
    ) 

    switch result.status { 
    case .success, .warning: 
        guard let variation = result.choice?.variations.first else { return } 

        let searchQuery = variation.payload.data.searchQuery 
        // "jeens" 

        let spellCheckedQuery = variation.payload.data.spellCheckedQuery 
        // "jeans" 

        let normalizedQuery = variation.payload.data.normalizedQuery  

    case .error: 
        if let error = result.error { 
            print(error) 
        } 
    } 
} 

Visual Search

Parameters

ParameterData Structure TypeMandatory?Description
pagePageYesProvides screen context for the visual search request
imageBase64StringYesBase64‑encoded image to use for product matching
filters[Filter]?NoOptional attribute filters (brand, color, price range, and so on)
sortBySortOptions?NoSorting rules (for example, by field or by relevance)
pageAttributes[String: PageAttribute]?NoKey–value attributes for campaign targeting or search context
branchIdString?NoBranch identifier for multi‑branch setups (stores, financial institutions, restaurants)
optionsSearchOptions?NoAdditional search configurations (for example, return analytics metadata)

Code example

func visualSearch() async { 
    let result = await DYSdk.shared().search.visualSearch( 
        page: Page.homePage(pageLocation: "location"), 
        imageBase64: "imageBase64", 
        filters: [Filter.stringFilter("color", ["blue"])], 
        sortBy: SortOptions.byField("relevance", SortOrderType.desc), 
        pageAttributes: ["source": PageAttribute("mobile")], 
        branchId: "visual-search-branch", 
        options: SearchOptions(returnAnalyticsMetadata: true) 
    ) 

    switch result.status { 
    case .success, .warning: 
        guard 
            let choice = result.choice, 
            let variation = choice.variations.first 
        else { 
            print("VisualSearch: No choice or variation returned for visual search result") 
            return 
        } 

        let data = variation.payload.data 
        let totalNumResults = data.totalNumResults 
        let custom = data.custom 

        print("VisualSearch: totalNumResults=\(String(describing: totalNumResults)), custom=\(String(describing: custom))")  

        // Handle product slots 
        data.slots?.forEach { slot in 
            let slotId = slot.slotId 
            let sku = slot.sku 

            print("VisualSearch: slotId=\(String(describing: slotId)), sku=\(String(describing: sku))") 

            guard let productData = slot.productData as? DefaultRecsProductData else { 
                print("VisualSearch: productData is not DefaultRecsProductData for slot \(String(describing: slotId))") 
                return 
            } 

            let groupId = productData.groupId 
            let name = productData.name 
            let url = productData.url 
            let price = productData.price 
            let inStock = productData.inStock 
            let imageUrl = productData.imageUrl 
            let categories = productData.categories 
            let keywords = productData.keywords 

            print( 
                """ 
                VisualSearch product: 
                  groupId=\(String(describing: groupId)), 
                  name=\(String(describing: name)), 
                  price=\(String(describing: price)), 
                  inStock=\(String(describing: inStock)), 
                  url=\(String(describing: url)) 
                """ 
            ) 

            print( 
                """ 
                VisualSearch product details: 
                  imageUrl=\(String(describing: imageUrl)), 
                  categories=\(String(describing: categories)), 
                  keywords=\(String(describing: keywords)) 
                """ 
            ) 
        } 

        // Handle facets 
        data.facets?.forEach { facet in 
            let column = facet.column 
            let displayName = facet.displayName 
            let valuesType = facet.valuesType 

            print( 
                """ 
                VisualSearch facet: 
                  column=\(column), 
                  displayName=\(String(describing: displayName)), 
                  valuesType=\(valuesType) 
                """ 
            ) 

            if let numberFacet = facet as? NumberFacet { 
                let min = numberFacet.min 
                let max = numberFacet.max 
                print("VisualSearch number facet range: min=\(String(describing: min)), max=\(String(describing: max))") 

            } else if let stringFacet = facet as? StringFacet { 
                stringFacet.values.forEach { value in 
                    let name = value.name 
                    let count = value.count 
                    print("VisualSearch string facet value: name=\(name), count=\(count)") 
                } 
            } 
        } 

        // Log warnings (if any) in the .warning case 
        if result.status == .warning, let warnings = result.warnings { 
            warnings.forEach { warning in 
                print("VisualSearch warning: \(warning)") 
            } 
        } 

    case .error: 
        if let error = result.error { 
            print("VisualSearch error: \(error)") 
        } else { 
            print("VisualSearch error: unknown error") 
        } 
    } 
}