- ViSearch Swift SDK and Demo Source Code
This SDK contains two sets of APIs that provide accurate, reliable and scalable search. Please use ProductSearch API for current latest version.
It is an open source software to provide easy integration of ViSearch APIs and ProductSearch APIs with your iOS applications. See the table below for more API specific information:
API | Description |
---|---|
ViSearch | Four search methods are provided based on the ViSearch legacy Solution APIs (Deprecated) - Find Similar, You May Also Like, Search By Image and Search By Color. For more details, see ViSearch API Documentation. |
ProductSearch | ViSenze Discovery Suite provides your customers a better and more intuitive product search and discovery experience by helping them search, navigate and interact with products more easily. The ProductSearch API provides a new set of product-based APIs that work with ViSenze Catalog Manager. In the SDK, ProductSearch API is refered to as ViProductSearch . |
For source code and references, please visit the Github Repository.
Current stable version:
1.11.0
(Swift 5+)Supported iOS version: iOS 8.x and higher
In Xcode, go to File > New > Project Select the Single View Application.
Type a name for your project and press Next, here we use Demo as the project name.
First you need to install the CocoaPods Ruby gem:
# Xcode 7 + 8
sudo gem install cocoapods --pre
Then go to your project directory to create an empty Podfile
cd /path/to/Demo
pod init
Edit the Podfile as follow. Please update the version to the latest. This is just a reference.
platform :ios, '12.0'
use_frameworks!
target '<Your Target Name>' do
pod 'ViSearchSDK', '~>1.11.0'
end
...
Install the ViSearch SDK:
pod install
The Demo.xcworkspace project should be created.
You can add ViSearchSDK to an Xcode project by adding it to your project as a package.
If you want to use Dependencies in a SwiftPM project, it's as
simple as adding it to your Package.swift
:
dependencies: [
.package(url: "https://github.com/visenze/visearch-sdk-swift", from: "1.11.0")
]
And then adding the product to any target that needs access to the library:
.product(name: "ViSearchSDK", package: "visearch-sdk-swift"),
- Create a Cartfile in the same directory where your
.xcodeproj
or.xcworkspace
is. - List the dependency as follow:
github "visenze/visearch-sdk-swift" ~> 1.11.0
. Please change the version to latest available version. - Run
carthage update --use-xcframeworks
orcarthage bootstrap --platform iOS --cache-builds --no-use-binaries --use-xcframeworks
. The command will fail asViSenzeAnalytics.xcframework
is not pulled as it is a dependency. We will resolve it in the next step. - A Cartfile.resolved file and a Carthage directory will appear in the same directory where your .xcodeproj or .xcworkspace is
- Navigate to ViSearchSDK folder:
cd Carthage/Checkouts/visearch-sdk-swift/ViSearchSDK
which contains the source code for ViSearchSDK. - Run
carthage update --use-xcframeworks
orcarthage bootstrap --platform iOS --cache-builds --no-use-binaries --use-xcframeworks
. This will pull and build Analytics dependency. - Return to the root directory where your
.xcodeproj
or.xcworkspace
is. - Run the carthage command again (same as step 3).
- The build will be successful.
- Drag the built
ViSearchSDK.xcframework
/ViSenzeAnalytics.framework
bundles from Carthage/Build into the "Frameworks and Libraries" section of your application’s Xcode project. - If you are using Carthage for an application, select "Embed & Sign", otherwise "Do Not Embed".
You can also download the iOS ViSearch SDK directly. To use it, unzip it and drag ViSearchSDK project (under ViSearchSDK folder) into your project. The ViSearchSDK project produces ViSearchSDK framework and has a dependency i.e. ViSenzeAnalytics. Before it can be used, you will need to run and pull ViSenzeAnalytics framework by running:
carthage update --use-xcframeworks
To verify the ViSearchSDK project can be compiled successfully, open ViSearchSDK.xcodeproj
, make sure it can be built successfully and ViSenzeAnalytics
framework is included under Frameworks and Libraries. If for some reasons, the framework is missing, you can also find it under ViSearchSDK/Carthage/Build/ViSenzeAnalytics.xcframework
path. You can manually add the framework to the project if missing.
After this, you can copy the ViSearchSDK folder into your project.
-
Open the
ViSearchSDK
folder, and drag theViSearchSDK.xcodeproj
into the Project Navigator of your application's Xcode project.It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter.
-
Select the
ViSearchSDK.xcodeproj
in the Project Navigator and verify the deployment target matches that of your application target. -
Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar.
-
In the tab bar at the top of that window, open the "General" panel.
-
Click on the
+
button under the "Embedded Binaries" section. -
Select the
ViSearchSDK.framework
.
The
ViSearchSDK.framework
is automagically added as a target dependency, linked framework and embedded framework.
You are done!
iOS 10 now requires user permission to access camera and photo library. If your app requires these access, please add description for NSCameraUsageDescription, NSPhotoLibraryUsageDescription in the Info.plist. More details can be found here.
ViSearch
must be initialized with an appKey
or accessKey
/secretKey
pair before it can be used.
import ViSearchSDK
...
// using default ViSearch client. The client, by default, will connect to Visenze's server
// recommended way of init ViSearch client with app key
ViSearch.sharedInstance.setup(appKey: "YOUR_APP_KEY")
// old way of init ViSearch client with access and secret key pair
ViSearch.sharedInstance.setup(accessKey: "YOUR_ACCESS_KEY", secret: "YOUR_SECRET_KEY")
...
// or using customized client, which connects to your own server
client = ViSearchClient(baseUrl: yourUrl, accessKey: accessKey, secret: secret)
...
Please init ViSearch client in this way if you connect to another endpoint rather than default (https://visearch.visenze.com)
client = ViSearchClient(baseUrl: "https://custom-visearch.yourdomain.com", accessKey: accessKey, secret: secret)
For searches in China, please change the endpoint to https://visearch.visenze.com.cn
.
By default, API search requests will timeout after 10s. To change the timeout, you can configure the client as below:
// configure timeout to 30s example. By default timeout is set 10s.
ViSearch.sharedInstance.client?.timeoutInterval = 30
ViSearch.sharedInstance.client?.sessionConfig.timeoutIntervalForRequest = 30
ViSearch.sharedInstance.client?.sessionConfig.timeoutIntervalForResource = 30
ViSearch.sharedInstance.client?.session = URLSession(configuration: (ViSearch.sharedInstance.client?.sessionConfig)!)
ProductSearch
must be initialized with an appKey
and placementId
before it can be used.
For searches in China, please set the baseUrl to https://search.visenze.com.cn
. For analytics, you will initialise the tracker with forCn
set to true.
import ViSearchSDK
// initialize ProductSearch API using app key and placement id
ViProductSearch.sharedInstance.setUp(appKey: "YOUR_KEY", placementId: YOUR_PLACEMENT_ID)
// custom search endpoint
ViProductSearch.sharedInstance.setUp(appKey: "YOUR_KEY", placementId: YOUR_PLACEMENT_ID, baseUrl:"https://custom-search.yourdomain.com")
// configure timeout to 30s example. By default timeout is set 10s.
ViProductSearch.sharedInstance.client?.timeoutInterval = 30
ViProductSearch.sharedInstance.client?.sessionConfig.timeoutIntervalForRequest = 30
ViProductSearch.sharedInstance.client?.sessionConfig.timeoutIntervalForResource = 30
ViProductSearch.sharedInstance.client?.session = URLSession(configuration: (ViProductSearch.sharedInstance.client?.sessionConfig)!)
If you want to create multiple instances of ProductSearch, you can instantiate ViProductSearch multiple times
var placement111 = ViProductSearch()
placement111.setUp(appKey: "YOUR_KEY", placementId: YOUR_PLACEMENT_ID)
var placement222 = ViProductSearch()
placement222.setUp(appKey: "YOUR_KEY", placementId: YOUR_PLACEMENT_ID)
GET /search
Visually Similar Recommendations solution is used to search for visually similar images in the image database giving an indexed image’s unique identifier (im_name).
import ViSearchSDK
...
let params = ViSearchParams(imName: "imName-example")
ViSearch.sharedInstance.findSimilar( params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
})
...
POST /uploadsearch
Search by image solution is used to search similar images by uploading an image or providing an image url. You should construct the UIImage
object and pass it to ViUploadSearchParams
to start a search.
- Using Image
import ViSearchSDK
...
let image = UIImage(named: "someImage.png")
let params = ViUploadSearchParams(image: image!)
ViSearch.sharedInstance.uploadSearch(params: params,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
})
- Alternatively, you can pass an image url directly to
ViUploadSearchParams
to start the search :
import ViSearchSDK
...
let params = ViUploadSearchParams(im_url: "http://somesite.com/sample_image.png")
ViSearch.sharedInstance.uploadSearch(params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
})
...
- Once uploading an image, you will receive a im_id attribute from the Search Results. If you want to search the same image again, you can save the bandwidth by specifying the im_id in the params:
import ViSearchSDK
...
let params = ViUploadSearchParams(im_id: "im_id_example")
ViSearch.sharedInstance.uploadSearch(params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
...
If the object you wish to search for takes up only a small portion of your image, or other irrelevant objects exists in the same image, chances are the search result could become inaccurate. Use the Box parameter to refine the search area of the image to improve accuracy. The box coordinated is set with respect to the original size of the uploading image. Note: the coordinate system uses pixel as unit instead of point.
// create the box to refine the area on the searching image
// ViBox(x1, y1, x2, y2) where (0,0) is the top-left corner
// of the image, (x1, y1) is the top-left corner of the box,
// and (x2, y2) is the bottom-right corner of the box.
...
let params = ViUploadSearchParams(.....)
let box = ViBox(x1: 0, y1: 0, x2: 100, y2: 100)
params!.box = box
// start searching
...
When performing upload search, you may notice the increased search latency with increased image file size. This is due to the increased time spent in network transferring your images to the ViSearch server, and the increased time for processing larger image files in ViSearch.
To reduce upload search latency, by default the uploadSearch method makes a copy of your image file and resizes the copy to 512x512 pixels if one of the original dimensions exceed 512 pixels. This is the optimized size to lower search latency while not sacrificing search accuracy for general use cases:
// by default, the max width of the image is set to 512px, quality is 0.97
let params = ViUploadSearchParams(.....)
// or you can explicitly set a param's settings
params?.img_settings = ViImageSettings(setting: .highQualitySetting)
If your image contains fine details such as textile patterns and textures, you can use an image with larger size for search to get better search result:
// by default, the max width of the image is set to 512px, quality is 0.97
let params = ViUploadSearchParams(.....)
// set the image with high quality settings.
// Max width is 1024px, and the quality is 0.985. Note: Quality with 1.0 take hugespace
params?.img_settings = ViImageSettings(setting: .highQualitySetting)
Or, provide the customized resize settings. To make efficient use the of the memory and network bandwidth of mobile device, the maximum size is set at 1024 x 1024. Any image exceeds the limit will be resized to the limit:
//resize the image to 800 by 800 area using jpeg 0.9 quality
params?.img_settings = ViImageSettings(size: CGSize(width: 800, height: 800), quality: 0.9)
GET /colorsearch
Search by color solution is used to search images with similar color by providing a color code. The color code should be in Hexadecimal and passed to ViColorSearchParams
as a String
.
import ViSearchSDK
...
let params = ViColorSearchParams(color: "ff00ff")
// alternately, you can pass UIColor object to the initializer
// let params = ViColorSearchParams(color: someUIColorObject)
client.colorSearch( params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \(err.localizedDescription)")
})
...
POST /discoversearch
Multiple Product Search solution is to search similar images by uploading an image or providing an image url, similar to Search by Image. Multiple Product Search is able to detect all objects in the image and return similar images for each at one time.
- Using Image
import ViSearchSDK
...
let image = UIImage(named: "someImage.png")
let params = ViUploadSearchParams(image: image!)
ViSearch.sharedInstance.discoverSearch(params: params,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
})
- Alternatively, you can pass an image url directly to
ViUploadSearchParams
to start the search :
import ViSearchSDK
...
let params = ViUploadSearchParams(im_url: "http://somesite.com/sample_image.png")
ViSearch.sharedInstance.discoverSearch(params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
})
...
- Once uploading an image, you will receive a im_id attribute from the Search Results. If you want to search the same image again, you can save the bandwidth by specifying the im_id in the params:
import ViSearchSDK
...
let params = ViUploadSearchParams(im_id: "im_id_example")
ViSearch.sharedInstance.discoverSearch(params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \\(err.localizedDescription)")
...
POST /v1/product/search_by_image
Searching by Image can be done with 3 different parameters - image URL, image ID, image File.
- Using Image URL
import ViSearchSDK
...
let params = ViSearchByImageParam(imUrl: "IMAGE_URL")
- Using Image ID (the ID can be retrieved from previous search responses)
import ViSearchSDK
...
let params = ViSearchByImageParam(im_id: "IMAGE_ID")
- Using an Image File (UIImage)
import ViSearchSDK
...
let params = ViSearchByImageParam(image: UIImage(contentsOfFile: "IMAGE_FILEPATH"))
Running the search:
ViProductSearch.sharedInstance.searchByImage(
params: params,
successHandler: {
(response: ViProductSearchResponse?) -> Void in
// your function to process response
},
failureHandler: {
(err: Error) -> Void in
// your function to handle error
}
)
GET /v1/product/recommendations/{product-id}
import ViSearchSDK
...
let params = ViSearchByIdParam(productId: "PRODUCT_ID")
ViProductSearch.sharedInstance.searchById(
successHandler: {
(response: ViProductSearchResponse?) -> Void in
// your function to process response
},
failureHandler: {
(err: Error) -> Void in
// your function to handle error
}
)
POST /v1/product/multisearch
import ViSearchSDK
...
let params = ViSearchByImageParam(image: UIImage(contentsOfFile: "IMAGE_FILEPATH"))
params.q = "my-text-query"
ViProductSearch.sharedInstance.multisearch(
params: params,
successHandler: {
(response: ViProductSearchResponse?) -> Void in
// your function to process response
},
failureHandler: {
(err: Error) -> Void in
// your function to handle error
}
)
POST /v1/product/multisearch/autocomplete
import ViSearchSDK
...
let params = ViSearchByImageParam(image: UIImage(contentsOfFile: "IMAGE_FILEPATH"))
params.q = "my-partial-text-query"
ViProductSearch.sharedInstance.multiSearchAutoComplete(
params: params,
successHandler: {
(response: ViAutoCompleteResponse?) -> Void in
// your function to process response
},
failureHandler: {
(err: Error) -> Void in
// your function to handle error
}
)
ViSearch
and ProductSearch
each have their own responses, but they share many similarities, more details can be found in this section.
After a successful search request, a list of results are passed to the callback function in the form of ViResponseData. You can use the following properties from the result to fulfill your own purpose.
Name | Type | Description |
---|---|---|
hasError | Bool | true if there are errors returned by Visenze server. |
error | [String] | return the error messages from server if there is any. |
result | [ViImageResult] | A list of image results returned from the server. |
reqId | String? | A request id which can be used for tracking. More details can be found in Section 7 |
im_id | String? | An image id returned in the result which represents a image just uploaded. It can be re-used to do an upload search on the same image again. More details in Search by image |
Below are the properties of a ViImageResult .
Name | Type | Description |
---|---|---|
im_name | String | the identify name of the image. |
im_url | String? | url of the image if available e.g. when set getAllFl to true or set fl property to include im_url |
score | Float? | A float value ranging from 0.0 to 1.0. Refer to Section 6.3 Result Score. |
metadataDict | Dictionary | Other metadata returned from server. Refer to Section 6.1 Retrieving Metadata. |
// example
ViSearch.sharedInstance.uploadSearch( params: params!,
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
if let data = data {
// check if that there is no error
if !data.hasError {
for imgResult in data.result {
// process img result
}
}
}
},
failureHandler: {
(err) -> Void in
// Do something when request fails e.g. due to network error
print ("error: \(err.localizedDescription)")
})
You can provide pagination parameters to control the paging of the image search results by configuring the basic search parameters in ViBaseSearchParams
. As the result is returned in a format of a list of images page by page, use limit
to set the number of results per page, page
to indicate the page number:
Name | Type | Description |
---|---|---|
page | Integer | Optional parameter to specify the page of results. The first page of result is 1. Defaults to 1. |
limit | Integer | Optional parameter to specify the result per page limit. Defaults to 10. |
// For example, when the server side has 60 items, the search operation will return
// the first 30 items with page = 1 and limit = 30. By changing the page to 2,
// the search will return the last 30 items.
...
params.page = 2;
params.limit = 30;
// start searching
...
After a successful search request, the result is passed to the callback function in the form of ViProductSearchResponse. You can use the following properties from the result to fulfill your own purpose.
Name | Type | Description |
---|---|---|
requestId | String | Same as ViSearch |
status | String | The request status, either “OK”, “warning”, or “fail” |
imageId | String | Image ID. Can be used to search again without reuploading |
page | Int | The result page number |
limit | Int | The number of results per page |
total | Int | Total number of search result. |
error | ViErrorMsg | Error message and code if the request was not successful i.e. when status is “warning” or “fail” |
productTypes | [ViProductType] | Detected product types and their bounding box in (x1,y1,x2,y2) format |
result | [ViProduct] | The list of products in the search results. Important fields for first release. If missing, it will be set to blank. Note that we are displaying customer’s original catalog fields in “data” field |
catalogFieldsMapping | [String:String] | Original catalog’s fields mapping |
facets | [ViFacet] | List of facet fields value and response for filtering |
productInfo | [String:Any] | Only applicable for VSR, return query product info |
objects | [ViProductObjectResult] | |
groupResults | [ViGroupResult] | Only applicable when group_by is set |
groupByKey | String | Only applicable when group_by is set |
querySysMeta | [String:String] | System meta for query image / product |
To retrieve metadata of your search results, provide a list of metadata keys as the fl
(field list) in the basic search property:
params!.fl = ["price","brand","im_url"]
To retrieve all metadata of your image results, specify get_all_fl
parameter and set it to true:
params.getAllFl = true;
In result callback you can read the metadata:
successHandler: {
(data : ViResponseData?) -> Void in
// Do something when request succeeds
// preview by calling : dump(data)
// check ViResponseData.hasError and ViResponseData.error for any errors return by ViSenze server
if let data = data {
// check if that there is no error
if !data.hasError {
for imgResult in data.result {
// process img result
// example: extract price meta-data if available in server
print imgResult.metadataDict["price"]
}
}
}
}
Only metadata of type string, int, and float can be retrieved from ViSearch. Metadata of type text is not available for retrieval.
To filter search results based on metadata values, provide a map of metadata key to filter value as the fq
(filter query) property:
...
// the type of "count" on db schema is int,
// so we can specify the value range, or do a value match
params?.fq["count"] = "0, 199"
params?.fq["count"] = "199"
// the type of "price" on db schema is float,
// so we can specify the value range, or do a value match
params?.fq["price"] = "0.0, 199.0"
params?.fq["price"] = "15.0"
// the type of "description" on db schema is string, so we can do a string match.
params?.fq["description"] = "wooden"
// start searching
...
Querying syntax for each metadata type is listed in the following table:
Type | FQ |
---|---|
string | Metadata value must be exactly matched with the query value, e.g. "Vintage Wingtips" would not match "vintage wingtips" or "vintage" |
text | Metadata value will be indexed using full-text-search engine and supports fuzzy text matching, e.g. "A pair of high quality leather wingtips" would match any word in the phrase |
int | Metadata value can be either:
|
float | Metadata value can be either
|
ViSearch image search results are ranked in descending order i.e. from the highest scores to the lowest, ranging from 1.0 to 0.0. By default, the score for each result is not returned. You can turn on the score parameter to retrieve the scores for each image result:
...
params.score = true; // result will include score for every image
// start searching
...
If you need to restrict search results from a minimum score to a maximum score, specify the score_min and/or score_max parameters:
...
params.score = true; // result will include score for every image
params.scoreMin = 0.3; // the minimum score is 0.3
params.scoreMax = 0.8; // the maximum score is 0.8
// start searching. Every image result will have a score within [0.3, 0.8].
...
With Automatic Object Recognition, ViSearch /uploadsearch API is smart to detect the objects present in the query image and suggest the best matched product type to run the search on.
You can turn on the feature in upload search by setting the API parameter "detection=all". We are now able to detect various types of fashion items, including Top
, Dress
, Bottom
, Shoe
, Bag
, Watch
and Indian Ethnic Wear
. The list is ever-expanding as we explore this feature for other categories.
Notice: This feature is currently available for fashion application type only. You will need to make sure your app type is configurated as "fashion" on ViSenze dashboard.
params.detection = "all";
You can use the Box parameter to restrict the image area [x1, y1, x2, y2] as the portion of your image to search for. When you input a box with 0 width and 0 height, eg. “box”:[574,224,574,224]. We will treat it as a point and detect the object over the current point.
You could also recognize objects from a paticular type on the uploaded query image through configuring the detection parameter to a specific product type as "detection={type}". Our API will run the search within that product type.
Sample request to detect bag
in an uploaded image:
params.detection = "bag";
The detected product types are listed in product_types
together with the match score and box area of the detected object. Multiple objects can be detected from the query image and they are ranked from the highest score to lowest. The full list of supported product types by our API will also be returned in product_types_list
.
You can get the facet results by sending a list of fields to enable faceting on. Here are some limitations on the request:
-
Facet fields need to be marked as
searchable
on ViSenze dashboard. Text field is not supported as facet field even it issearchable
. System will return value range, the min, max value for numerical fields which are in ‘int’, ‘float’ type. -
Only facet values that exist in current search results will be returned. For example, if your search results contain 10 unique brands, then the facet filters will return the value for these 10 brands.
-
Facet value list is ordered by the item count descendingly. When the value is set to all (facets = *), all the searchable fields will be used as facet fields.
Name | Type | Description |
---|---|---|
facets | array | List of fields to enable faceting. |
facets_limit | Int | Limit of the number of facet values to be returned. Only for non-numerical fields. |
facets_show_count | Boolean | Option to show the facets count in the response. |
params?.facets = ["price", "brand"]
params?.facetsLimit = 10
params?.facetShowCount = true
// view facet results
ViResponseData.facets
// numerical facet would have a min and max
// ViFacet.min , ViFacet.max
// string fields would have a count (if facetShowCount is set )
// ViFacet.items
To improve search performance and gain useful data insights, it is recommended to send user interactions (actions) with our visual search results.
You can initiliase ViSenze tracker as follows depending on whether you are using new ViSenze Console (console.visenze.com) or ViSenze Dashboard (dashboard.visenze.com).
import ViSearch
...
# for ViSenze Console
let tracker = ViProductSearch.sharedInstance.newTracker()
# for sending events in China
let cnTracker = ViProductSearch.sharedInstance.newTracker(forCn: true)
# for ViSenze old dashboard
let tracker = ViSearch.sharedInstance.newTracker(code: "your-code")
To get ViSenze autogenerated uid
and session Id for analytics purposes, you can call
// get uid
ViProductSearch.sharedInstance.getUid()
// get session ID
ViProductSearch.sharedInstance.getSid()
If you want to create multiple instances of tracker, you can instantiate ViSenzeTracker multiple times
var placement111 = ViProductSearch()
placement111.setUp(appKey: "YOUR_KEY", placementId: YOUR_PLACEMENT_ID)
var tracker111 = placement111.newTracker()
var placement222 = ViProductSearch()
placement222.setUp(appKey: "YOUR_KEY", placementId: YOUR_PLACEMENT_ID)
var tracker222 = placement222.newTracker()
Currently we support the following event actions: click
, view
, product_click
, product_view
, add_to_cart
, add_to_wishlist
and transaction
. The action
parameter can be an arbitrary string and custom events can be sent.
Note that it is optional to send transaction ID, product image URL and product position. You can create the event using the corresponding methods such as VaEvent.newProductClickEvent (queryId: "", pid: "")
if you do not have other fields.
To send events, first retrieve the search query ID found in the search results call back:
successHandler: {
(data : ViResponseData?) -> Void in
if let data = data {
let queryId = data.reqId
}
}
Then the linked events can be sent as follows:
# send product click
let productClickEvent = VaEvent.newProductClickEvent(queryId: "ViSearch reqid in API response", pid: "product ID", imgUrl: "product image URL", pos: 3)
tracker.sendEvent(productClickEvent) { (eventResponse, networkError) in
}
# send product impression
let impressionEvent = VaEvent.newProductImpressionEvent(queryId: "ViSearch reqid in API response", pid: "product ID", imgUrl: "product image URL", pos: 3)
tracker.sendEvent(impressionEvent)
# send Transaction event e.g order purchase of $300
let transEvent = VaEvent.newTransactionEvent(queryId: "xxx", transactionId:"your trans id", value: 300)
tracker.sendEvent(transEvent)
# send Add to Cart Event
let add2Cart = VaEvent.newAdd2CartEvent(queryId: "ViSearch reqid in API response", pid: "product ID", imgUrl: "product image URL", pos: 3)
tracker.sendEvent(add2Cart)
# send result load event
let resLoadEvent = VaEvent.newResultLoadEvent(queryId: "xxx", pid:"your query product id")
tracker.sendEvent(resLoadEvent)
User action(s) can also be sent through an batch event handler.
A common use case for this batch event method is to group up all transactions by sending it in a batch. This SDK will automatically generate a transaction ID to group transactions as an order.
tracker.sendEvents(eventList)
Below are the brief description for various parameters:
Field | Description | Required |
---|---|---|
queryId | The request id of the search request. This reqid can be obtained from the search response handler:ViResponseData.reqId |
Yes |
action | Event action. Currently we support the following event actions: click , view , product_click , product_view , add_to_cart , and transaction . |
Yes |
pid | Product ID ( generally this is the im_name ) for this product. Can be retrieved via ViImageResult.im_name |
Required for product view, product click and add to cart events |
imgUrl | Image URL ( generally this is the im_url ) for this product. Can be retrieved via ViImageResult.im_url |
Required for product view, product click and add to cart events |
pos | Position of the product in Search Results e.g. click position/ view position. Note that this start from 1 , not 0. | Required for product view, product click and add to cart events |
transactionId | Transaction ID | Required for transaction event. |
value | Transaction value e.g. order value | Required for transaction event. |
uid | Unique user/device ID. If not provided, a random (non-personalizable) UUID will be generated to track the browser. | No |
category | A generic string to categorize / group the events in related user flow. For example: privacy_flow , videos , search_results . Typically, categories are used to group related UI elements. Max length: 32 |
No |
name | Event name e.g. open_app , click_on_camera_btn . Max length: 32. |
No |
label | label for main interaction object such as product title, page title. This together with action can be used to decide whether an event is unique e.g. if user clicks on same product twice, only 1 unique click . Max length: 32. |
No |
fromReqId | Generic request ID field to specify which request leads to this event e.g. click request ID that leads to the purchase. The chain can be like this queryId → clickId → purchase. Max length: 32. | No |
source | Segment the traffic by tagging them e.g. from camera, from desktop. Max length: 32. | No |
brand | Product brand. Max length: 64. | No |
price | Product price. Numeric field, if provided must be >=0 and is a valid number. | No |
currency | ISO 3 characters code e.g. “USD”. Will be validated if provided. | No |
productUrl | Product URL. Max length: 512 | No |
campaign | Advertising campaign. Max length : 64. | No |
adGroup | Ad group name (only relevant for campaign) | No |
creative | Creative name (only relevant for campaign) | No |
n1 | Custom numeric parameter. | No |
n2 | Custom numeric parameter. | No |
n3 | Custom numeric parameter. | No |
n4 | Custom numeric parameter. | No |
n5 | Custom numeric parameter. | No |
s1 | Custom string parameter. Max length: 64. | No |
s2 | Custom string parameter. Max length: 64. | No |
s3 | Custom string parameter. Max length: 64. | No |
s4 | Custom string parameter. Max length: 64. | No |
s5 | Custom string parameter. Max length: 64. | No |
json | Custom json parameter. Max length: 512. | No |
The SDK requires ViSenze Tracking library as a dependency https://github.com/visenze/visenze-tracking-swift. For local development, the dependency can be pulled by running the following within ViSearchSDK
folder.
# first update version within Cartfile
# pull latest changes and build framework
carthage update --use-xcframeworks