# Visually similar

- Operation ID: `GetSimilarVisualItems`
- HTTP method: `GET`
- Path: `/recommendations/v2/recommend/items/{itemId}/similar/visual`
- [Human-readable API reference](https://hub.synerise.com/api-reference/campaigns#operation/GetSimilarVisualItems)

## Self-contained OpenAPI method

The fenced document below contains this method's documentation and all of its local references. It is self-contained; no category or master specification fetch is required.

```yaml
openapi: 3.0.0
info:
  title: Synerise Public API
  version: 1.9.5
paths:
  /recommendations/v2/recommend/items/{itemId}/similar/visual:
    get:
      summary: Visually similar
      description: |
        Returns items visually similar to the given items.

        **Note:** The definition of an *item* encompasses products, but also articles, images, videos, and any other entities in the item feed.

        ---

        **API consumers:** <span title="Deprecated">AI API key (legacy)</span>, <a href="/api-reference/authorization?tag=Authorization&amp;operationId=profileLogin" target="_blank" rel="noopener">Workspace (Business Profile)</a>, <a href="/docs/settings/tool/tracking_codes" target="_blank" rel="noopener" title="Pass your tracker key in the request header">Web SDK Tracker</a>

        **API key permission required:** `RECOMMENDATIONS_V2_VISUAL_RECOMMENDATIONS_READ`
      operationId: GetSimilarVisualItems
      tags:
        - Recommendations
      security:
        - TrackerKey: []
        - JWT: []
        - BasicAuth: []
      parameters:
        - name: minNumItems
          in: query
          required: false
          description: The minimal number of returned item recommendations. If the service is not able to return at least this many recommendations, it will return an error.
          schema:
            type: integer
            description: The minimal number of returned item recommendations. If the service is not able to return at least this many recommendations, it will return an error.
            default: 1
            minimum: 1
        - name: maxNumItems
          in: query
          required: false
          description: The maximal number of returned item recommendations.
          schema:
            type: integer
            description: The maximal number of returned item recommendations.
            maximum: 100
            default: 5
        - name: clientUUID
          in: query
          description: |
            Profile UUID. This parameter is required for these recommendation types:
              - Personalized
              - Last seen
              - Recent interactions
              - Section
              - Attribute

            This parameter can be passed in all recommendations. In recommendations which don't require the customer context, it can still be used to create filters.
          required: false
          schema:
            type: string
        - in: path
          name: itemId
          required: true
          description: Item identifier, equal to `itemId` from the *item feed*.
          schema:
            type: string
        - name: excludePurchasedItems
          in: query
          required: false
          description: |
            When true, the recommendation results will include only items that the profile hasn't purchased before.  
            **IMPORTANT**: Only the last 250 purchased items are taken into account. Items further back in the purchase history may be included in the recommendation.
          schema:
            description: |
              When true, the recommendation results will include only items that the Profile hasn't purchased before.  
              **IMPORTANT**: Only the last 250 purchased items are taken into account. Items further back in the purchase history may be included in the recommendation.
            type: boolean
            default: false
        - name: excludePurchasedItemsSinceDays
          in: query
          required: false
          description: Limits the application of the `excludePurchasedItems` filter to a specified number of days.
          schema:
            description: Limits the application of the `excludePurchasedItems` filter to a specified number of days.
            type: integer
        - name: filters
          in: query
          required: false
          description: |
            This string defines the criteria that an item must meet in order to be considered for recommendation.  
            For information on building filters, see ["Items Query Language (IQL)" in the Developer Guide](https://hub.synerise.com/developers/iql/).
          schema:
            type: string
        - name: elastic:filters
          in: query
          required: false
          description: |
            This string defines the criteria that an item must meet in order to be considered for recommendation. The Elastic filter may be dropped if not enough products meet the required criteria.  
            For information on building filters, see ["Items Query Language (IQL)" in the Developer Guide](https://hub.synerise.com/developers/iql/).
          schema:
            type: string
        - name: itemCatalogId
          in: query
          required: false
          description: ID (_not_ name) of the item feed to use in the request. The requested recommendation type (model) must be ready for this item feed.
          schema:
            type: string
            default: default
        - name: campaignId
          in: query
          required: false
          description: The campaignId which will be passed as *utm_campaign* in a link to the recommended item.
          schema:
            type: string
            default: defaultCampaign
        - name: campaignName
          in: query
          required: false
          description: The campaign name which will be included in the recommendation.generated event.
          schema:
            type: string
        - in: query
          name: distinctFilter
          required: false
          schema:
            type: object
            description: Distinct filters allow you to specify how many recommended items can have the same value of specified attributes.
            properties:
              elastic:
                type: boolean
                description: When TRUE, allows to complete the recommended items with items which don't meet the distinct filter criteria.
              filters:
                type: array
                minItems: 1
                maxItems: 5
                description: Array of distinct filters
                items:
                  type: object
                  properties:
                    field:
                      type: string
                      description: Attribute name
                    maxNumItems:
                      type: number
                      format: integer
                      description: Max number of items with the same value of the attribute
                    levelRangeModifier:
                      type: number
                      format: integer
                      description: Parameter used (for the `category` field) to specify how many categories to cut off from the end
                  required:
                    - field
                    - maxNumItems
            required:
              - elastic
              - filters
        - name: includeContextItems
          in: query
          required: false
          description: The recommendation results will include context items from the request.
          schema:
            type: boolean
        - name: params
          in: query
          required: false
          description: |
            List of extra params that will be added to the `recommendation.generated` event. They must be in the `name:value` format. The total size must not exceed 500 bytes when written as a JSON object.
          example:
            - source:mobile
          schema:
            type: array
            items:
              type: string
        - name: inventoryChannelId
          in: query
          required: false
          description: |
            Inventory context identifier used to evaluate inventory-related filters and boosting strategies. If not provided, no inventory context will be applied.
          schema:
            type: string
        - name: crossWorkspaceMode
          in: query
          required: false
          description: |
            Specifies if recommendation should use cross-workspace mode and personalize recommendations with events from other members of workspace group if they are available.
          schema:
            type: boolean
      responses:
        "200":
          description: Items visually similar to the given item
          content:
            application/json:
              schema:
                type: object
                properties:
                  extras:
                    type: object
                    description: Additional data
                    properties:
                      correlationId:
                        type: string
                        description: Correlation ID that allows you to link the "item clicked" events with the "recommendation generated" event that's created for each recommendation result.
                      contextItems:
                        type: array
                        nullable: true
                        description: A list of context items provided in the request
                        items:
                          type: object
                          properties:
                            itemId:
                              type: string
                              description: Item identifier (`itemId` in item catalog)
                          additionalProperties: true
                          required:
                            - itemId
                      campaignId:
                        type: string
                        description: ID of the context campaign
                        nullable: true
                  data:
                    type: array
                    description: A list of recommended items
                    items:
                      type: object
                      properties:
                        itemId:
                          type: string
                          description: Item identifier (`itemId` in item catalog)
                      additionalProperties: {}
                      required:
                        - itemId
        "404":
          description: No recommendations could be generated for the specified profile and filters
          content:
            application/json:
              schema:
                type: object
                description: Details of an error, if applicable
                properties:
                  timestamp:
                    type: string
                    format: date-time
                    description: Time when the error occurred
                  status:
                    type: integer
                    description: Status code
                  error:
                    type: string
                    description: Summary of the error
                  message:
                    type: string
                    description: Description of the problem
                  path:
                    type: string
                    description: URL of the requested resource
                required:
                  - timestamp
                  - status
                  - message
        "500":
          description: An error occurred
          content:
            application/json:
              schema:
                type: object
                description: Details of an error, if applicable
                properties:
                  timestamp:
                    type: string
                    format: date-time
                    description: Time when the error occurred
                  status:
                    type: integer
                    description: Status code
                  error:
                    type: string
                    description: Summary of the error
                  message:
                    type: string
                    description: Description of the problem
                  path:
                    type: string
                    description: URL of the requested resource
                required:
                  - timestamp
                  - status
                  - message
      x-snr-doc-urls:
        - /api-reference/ai-recommendations#tag/Recommendations/operation/GetSimilarVisualItems
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |-
            curl --request GET \
              --url 'https://api.synerise.com/recommendations/v2/recommend/items/%7BitemId%7D/similar/visual?minNumItems=SOME_INTEGER_VALUE&maxNumItems=SOME_INTEGER_VALUE&clientUUID=SOME_STRING_VALUE&excludePurchasedItems=SOME_BOOLEAN_VALUE&excludePurchasedItemsSinceDays=SOME_INTEGER_VALUE&filters=SOME_STRING_VALUE&elastic%3Afilters=SOME_STRING_VALUE&itemCatalogId=SOME_STRING_VALUE&campaignId=SOME_STRING_VALUE&campaignName=SOME_STRING_VALUE&distinctFilter=SOME_OBJECT_VALUE&includeContextItems=SOME_BOOLEAN_VALUE&params=source%3Amobile&inventoryChannelId=SOME_STRING_VALUE&crossWorkspaceMode=SOME_BOOLEAN_VALUE' \
              --header 'Authorization: Basic REPLACE_BASIC_AUTH'
        - lang: Python
          label: Python
          source: |-
            import http.client

            conn = http.client.HTTPSConnection("api.synerise.com")

            headers = { 'Authorization': "Basic REPLACE_BASIC_AUTH" }

            conn.request("GET", "/recommendations/v2/recommend/items/%7BitemId%7D/similar/visual?minNumItems=SOME_INTEGER_VALUE&maxNumItems=SOME_INTEGER_VALUE&clientUUID=SOME_STRING_VALUE&excludePurchasedItems=SOME_BOOLEAN_VALUE&excludePurchasedItemsSinceDays=SOME_INTEGER_VALUE&filters=SOME_STRING_VALUE&elastic%3Afilters=SOME_STRING_VALUE&itemCatalogId=SOME_STRING_VALUE&campaignId=SOME_STRING_VALUE&campaignName=SOME_STRING_VALUE&distinctFilter=SOME_OBJECT_VALUE&includeContextItems=SOME_BOOLEAN_VALUE&params=source%3Amobile&inventoryChannelId=SOME_STRING_VALUE&crossWorkspaceMode=SOME_BOOLEAN_VALUE", headers=headers)

            res = conn.getresponse()
            data = res.read()

            print(data.decode("utf-8"))
        - lang: JavaScript
          label: JavaScript
          source: |-
            const data = null;

            const xhr = new XMLHttpRequest();
            xhr.withCredentials = true;

            xhr.addEventListener("readystatechange", function () {
              if (this.readyState === this.DONE) {
                console.log(this.responseText);
              }
            });

            xhr.open("GET", "https://api.synerise.com/recommendations/v2/recommend/items/%7BitemId%7D/similar/visual?minNumItems=SOME_INTEGER_VALUE&maxNumItems=SOME_INTEGER_VALUE&clientUUID=SOME_STRING_VALUE&excludePurchasedItems=SOME_BOOLEAN_VALUE&excludePurchasedItemsSinceDays=SOME_INTEGER_VALUE&filters=SOME_STRING_VALUE&elastic%3Afilters=SOME_STRING_VALUE&itemCatalogId=SOME_STRING_VALUE&campaignId=SOME_STRING_VALUE&campaignName=SOME_STRING_VALUE&distinctFilter=SOME_OBJECT_VALUE&includeContextItems=SOME_BOOLEAN_VALUE&params=source%3Amobile&inventoryChannelId=SOME_STRING_VALUE&crossWorkspaceMode=SOME_BOOLEAN_VALUE");
            xhr.setRequestHeader("Authorization", "Basic REPLACE_BASIC_AUTH");

            xhr.send(data);
        - lang: Node.js
          label: Node.js
          source: |-
            const http = require("https");

            const options = {
              "method": "GET",
              "hostname": "api.synerise.com",
              "port": null,
              "path": "/recommendations/v2/recommend/items/%7BitemId%7D/similar/visual?minNumItems=SOME_INTEGER_VALUE&maxNumItems=SOME_INTEGER_VALUE&clientUUID=SOME_STRING_VALUE&excludePurchasedItems=SOME_BOOLEAN_VALUE&excludePurchasedItemsSinceDays=SOME_INTEGER_VALUE&filters=SOME_STRING_VALUE&elastic%3Afilters=SOME_STRING_VALUE&itemCatalogId=SOME_STRING_VALUE&campaignId=SOME_STRING_VALUE&campaignName=SOME_STRING_VALUE&distinctFilter=SOME_OBJECT_VALUE&includeContextItems=SOME_BOOLEAN_VALUE&params=source%3Amobile&inventoryChannelId=SOME_STRING_VALUE&crossWorkspaceMode=SOME_BOOLEAN_VALUE",
              "headers": {
                "Authorization": "Basic REPLACE_BASIC_AUTH"
              }
            };

            const req = http.request(options, function (res) {
              const chunks = [];

              res.on("data", function (chunk) {
                chunks.push(chunk);
              });

              res.on("end", function () {
                const body = Buffer.concat(chunks);
                console.log(body.toString());
              });
            });

            req.end();
        - lang: PHP
          label: PHP
          source: |-
            <?php

            $request = new HttpRequest();
            $request->setUrl('https://api.synerise.com/recommendations/v2/recommend/items/%7BitemId%7D/similar/visual');
            $request->setMethod(HTTP_METH_GET);

            $request->setQueryData([
              'minNumItems' => 'SOME_INTEGER_VALUE',
              'maxNumItems' => 'SOME_INTEGER_VALUE',
              'clientUUID' => 'SOME_STRING_VALUE',
              'excludePurchasedItems' => 'SOME_BOOLEAN_VALUE',
              'excludePurchasedItemsSinceDays' => 'SOME_INTEGER_VALUE',
              'filters' => 'SOME_STRING_VALUE',
              'elastic:filters' => 'SOME_STRING_VALUE',
              'itemCatalogId' => 'SOME_STRING_VALUE',
              'campaignId' => 'SOME_STRING_VALUE',
              'campaignName' => 'SOME_STRING_VALUE',
              'distinctFilter' => 'SOME_OBJECT_VALUE',
              'includeContextItems' => 'SOME_BOOLEAN_VALUE',
              'params' => 'source:mobile',
              'inventoryChannelId' => 'SOME_STRING_VALUE',
              'crossWorkspaceMode' => 'SOME_BOOLEAN_VALUE'
            ]);

            $request->setHeaders([
              'Authorization' => 'Basic REPLACE_BASIC_AUTH'
            ]);

            try {
              $response = $request->send();

              echo $response->getBody();
            } catch (HttpException $ex) {
              echo $ex;
            }
        - lang: Java
          label: Java
          source: |-
            HttpResponse<String> response = Unirest.get("https://api.synerise.com/recommendations/v2/recommend/items/%7BitemId%7D/similar/visual?minNumItems=SOME_INTEGER_VALUE&maxNumItems=SOME_INTEGER_VALUE&clientUUID=SOME_STRING_VALUE&excludePurchasedItems=SOME_BOOLEAN_VALUE&excludePurchasedItemsSinceDays=SOME_INTEGER_VALUE&filters=SOME_STRING_VALUE&elastic%3Afilters=SOME_STRING_VALUE&itemCatalogId=SOME_STRING_VALUE&campaignId=SOME_STRING_VALUE&campaignName=SOME_STRING_VALUE&distinctFilter=SOME_OBJECT_VALUE&includeContextItems=SOME_BOOLEAN_VALUE&params=source%3Amobile&inventoryChannelId=SOME_STRING_VALUE&crossWorkspaceMode=SOME_BOOLEAN_VALUE")
              .header("Authorization", "Basic REPLACE_BASIC_AUTH")
              .asString();
servers:
  - url: https://api.synerise.com
    description: Microsoft Azure EU
  - url: https://api.azu.synerise.com
    description: Microsoft Azure USA
  - url: https://api.geb.synerise.com
    description: Google Cloud Platform
tags:
  - name: Recommendations
components:
  securitySchemes:
    TrackerKey:
      type: apiKey
      in: query
      name: token
      description: |
        Authentication by tracker key sent in a `token` query parameter. This can be the same key as used in the tracking code of the website. For details, see:

        - [Creating tracking codes](https://hub.synerise.com/developers/web/installation-and-configuration/#creating-a-tracking-code)
        - [Authenticating API requests with the tracker key](https://hub.synerise.com/developers/api/api-authorization/client-login/#tracker-key-authentication)
    JWT:
      type: http
      scheme: bearer
      description: |
        Synerise uses [JSON Web Token (JWT)](https://jwt.io/) as the authorization method.

        The token is generated by the *auth/login* endpoints.

        You need to include it in the `Authorization` header of your requests, with a `Bearer` prefix.


        By default, the token is valid for **one week** (see [workspace settings](https://hub.synerise.com/docs/settings/tool/iam-for-apps/general/#jwt-lifetime)).  
        You can request a refreshed key for the session by using the *auth/refresh* endpoint **before** the current token expires.


        You can verify your JWT signature by using the [public key](https://api.synerise.com/v4/public.pem).


        See Developer Guides on JWT API authentication for:
        - [profiles](https://hub.synerise.com/developers/api/api-authorization/client-login/);
        - [workspaces](https://hub.synerise.com/developers/api/api-authorization/workspace-login/#api-authentication-with-jwt);
        - [users](https://hub.synerise.com/developers/api/api-authorization/user-login/).
    BasicAuth:
      type: http
      scheme: basic
      description: |
        Basic authentication with login (workspace GUID) and password (workspace API key) encoded with Base64 and sent in the `Authorization` header. **Must be enabled in the settings of the API key**.

        <span style="color:red">This is less secure than JWTs.</span> Limit the API key permissions to only those that you need. Consider API key rotation and other security measures.

        You can still use JWTs from the same API key when basic authentication is enabled.

        For details, see ["Workspace authentication"](https://hub.synerise.com/jwt-or-basic/#basic-api-authentication-with-api-keys).
```
