Install Search by Image

Edit on GitHub

Search by Image lets storefront customers upload a photo to find products. AI analyzes the image, identifies a search term, and redirects the customer to the search results page or the first matching product detail page. This document describes how to install the Search by Image feature.

Install the feature core

Follow the steps in the following sections to install the Search by Image feature core.

Prerequisites

Install the required features:

NAME VERSION INSTALLATION GUIDE
AI Commerce 202602.0 Install AI Commerce
Configuration Management 202602.0 Install the Configuration Management feature
Catalog 202602.0

1) Add translations

Append the glossary according to your configuration: data/import/common/common/glossary.csv

>ai_commerce.search_by_image.form.image.label,Search by image,en_US
ai_commerce.search_by_image.form.image.label,Bildersuche,de_DE
ai_commerce.search_by_image.form.image.error.mime_type,"This image type is not supported. Please upload a JPEG, PNG, WebP, or GIF.",en_US
ai_commerce.search_by_image.form.image.error.mime_type,"Dieses Bildformat wird nicht unterstützt. Bitte laden Sie ein JPEG, PNG, WebP oder GIF hoch.",de_DE
ai_commerce.search_by_image.error.no_image_provided,Please select an image to search.,en_US
ai_commerce.search_by_image.error.no_image_provided,Bitte wählen Sie ein Bild für die Suche aus.,de_DE
ai_commerce.search_by_image.error.search_failed,Search by Image failed. Please try again.,en_US
ai_commerce.search_by_image.error.search_failed,Bildsuche fehlgeschlagen. Bitte versuchen Sie es erneut.,de_DE
ai_commerce.search_by_image.error.unavailable,Search by Image is currently unavailable. Please try again later.,en_US
ai_commerce.search_by_image.error.unavailable,Bildsuche ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut.,de_DE
ai_commerce.search_by_image.error.disabled,Search by Image is currently disabled.,en_US
ai_commerce.search_by_image.error.disabled,Bildsuche ist derzeit deaktiviert.,de_DE
ai_commerce.search_by_image.search,Search,en_US
ai_commerce.search_by_image.search,Suchen,de_DE
ai_commerce.search_by_image.upload_image,Upload image,en_US
ai_commerce.search_by_image.upload_image,Bild hochladen,de_DE
ai_commerce.search_by_image.upload_image_to_find_products,Upload an image to find similar products.,en_US
ai_commerce.search_by_image.upload_image_to_find_products,"Laden Sie ein Bild hoch, um ähnliche Produkte zu finden.",de_DE
ai_commerce.error.file.size.invalid,"File size is too big.",en_US
ai_commerce.error.file.size.invalid,"Ungültige Gesamtdateigröße.",de_DE
ai_commerce.search_by_image.image.description,"Max up to %size% MB. Allowed file formats %format%",en_US
ai_commerce.search_by_image.image.description,"Maximal bis zu %size%. Erlaubte Dateiformate: %format%",de_DE

Import the data:

console data:import glossary
Verification

Make sure that the configured data has been added to the spy_glossary_key and spy_glossary_translation tables.

2) Set up transfer objects

Generate transfer changes:

console transfer:generate
Verification

Make sure the following transfers have been created:

TRANSFER TYPE EVENT PATH
SearchByImageRequest class created src/Generated/Shared/Transfer/SearchByImageRequestTransfer.php
SearchByImageResponse class created src/Generated/Shared/Transfer/SearchByImageResponseTransfer.php
SearchByImagePromptResponse class created src/Generated/Shared/Transfer/SearchByImagePromptResponseTransfer.php

3) Register plugins

Register the following plugins:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
SearchByImageRouteProviderPlugin Registers the routes required for the Search by Image request handling. SprykerFeature\Yves\AiCommerce\SearchByImage\Plugin\Router
ImageSearchAiWidget Renders the camera icon and image upload dialog next to the search input. SprykerFeature\Yves\AiCommerce\SearchByImage\Widget

src/Pyz/Yves/Router/RouterDependencyProvider.php

<?php

namespace Pyz\Yves\Router;

use SprykerFeature\Yves\AiCommerce\SearchByImage\Plugin\Router\SearchByImageRouteProviderPlugin;
use SprykerShop\Yves\ShopApplication\Plugin\Provider\ShopControllerEventHandlerPlugin;

class RouterDependencyProvider extends SprykerRouterDependencyProvider
{
    /**
     * @return array<\Spryker\Yves\RouterExtension\Dependency\Plugin\RouteProviderPluginInterface>
     */
    protected function getRouteProvider(): array
    {
        return [
            // ...
            new SearchByImageRouteProviderPlugin(),
        ];
    }
}

Warm up the router cache:

console router:cache:warm-up

src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php

<?php

namespace Pyz\Yves\ShopApplication;

use SprykerFeature\Yves\AiCommerce\SearchByImage\Widget\ImageSearchAiWidget;
use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    /**
     * @return array<string>
     */
    protected function getGlobalWidgets(): array
    {
        return [
            // ...
            ImageSearchAiWidget::class,
        ];
    }
}
Verification

Make sure that the ImageSearchAiWidget is registered and the camera icon is rendered next to the search bar when the feature is enabled.

4) Configure AiFoundation for Search by Image

For a base AiFoundation setup, see Configure AiFoundation.

Using a dedicated AI configuration for Search by Image is recommended because each named configuration is tracked separately in the AiFoundation audit log. This lets you isolate and review all AI calls made by the image search flow independently from other AI features in your project.

To use a dedicated AI model configuration for Search by Image instead of the default one, follow these steps:

  1. In config/Shared/config_ai.php, add a named configuration entry using AiCommerceConstants::SEARCH_BY_IMAGE_CONFIGURATION_NAME as the key:
$config[\Spryker\Shared\AiFoundation\AiFoundationConstants::AI_CONFIGURATIONS][\SprykerFeature\Shared\AiCommerce\AiCommerceConstants::SEARCH_BY_IMAGE_CONFIGURATION_NAME] = [
    'provider_name' => \Spryker\Shared\AiFoundation\AiFoundationConstants::PROVIDER_OPENAI,
    'provider_config' => [
        'key' => getenv('OPEN_AI_API_TOKEN') ?: '',
        'model' => 'gpt-4o',
    ],
];
  1. Return the configuration name from AiCommerceConfig:

src/Pyz/Yves/AiCommerce/AiCommerceConfig.php

<?php

namespace Pyz\Yves\AiCommerce;

use SprykerFeature\Shared\AiCommerce\AiCommerceConstants;
use SprykerFeature\Yves\AiCommerce\AiCommerceConfig as SprykerAiCommerceConfig;

class AiCommerceConfig extends SprykerAiCommerceConfig
{
    public function getSearchByImageAiConfigurationName(): ?string
    {
        return AiCommerceConstants::SEARCH_BY_IMAGE_CONFIGURATION_NAME;
    }
}

5) Sync configuration

Sync the Search by Image configuration to the database:

console configuration:sync

6) Enable the feature

Enable the feature in the Back Office Configuration:

  1. In the Back Office, go to Configuration.
  2. Navigate to AI Commerce > Search by Image > Search by Image.
  3. Turn on Enable Search by Image.
  4. Set Redirect type to the desired behavior:
    • Search results — redirects the customer to the catalog search results page for the identified search term.
    • First result product detail page — redirects the customer directly to the product detail page of the first matching result.
  5. Click Save.

Search by Image configuration

Verification

On the Storefront, make sure the camera icon is visible next to the search bar.

Integrate the feature frontend

Note

The Twig template changes in this section reflect the current implementation. These templates may be updated in future releases. Review the latest demo shop templates before applying them at the project level.

1) Add icon sprites

Info

Do this step only if you have overridden icon-sprite.twig in the ShopUi module at the project level. If you have not overridden this template, skip to 2) Update the search form template.

In src/Pyz/Yves/ShopUi/Theme/default/components/atoms/icon-sprite/icon-sprite.twig, add the following SVG symbol definitions inside the {% block sprite %} block:


<symbol id=":upload-image" viewBox="0 -960 960 960" fill="currentColor">
    <title id=":upload-image">Upload Image</title>
    <path d="M480-480ZM224.62-160q-27.62 0-46.12-18.5Q160-197 160-224.62v-510.76q0-27.62 18.5-46.12Q197-800 224.62-800h280v40h-280q-10.77 0-17.7 6.92-6.92 6.93-6.92 17.7v510.76q0 10.77 6.92 17.7 6.93 6.92 17.7 6.92h510.76q10.77 0 17.7-6.92 6.92-6.93 6.92-17.7v-280h40v280q0 27.62-18.5 46.12Q763-160 735.38-160H224.62Zm46.15-144.62h418.46L560-476.92 440-325.38l-80-96.16-89.23 116.92ZM680-600v-80h-80v-40h80v-80h40v80h80v40h-80v80h-40Z"/>
</symbol>
<symbol id=":visual-search" viewBox="0 -960 960 960" fill="currentColor">
    <title id=":visual-search">Visual Search</title>
    <path d="M367-367q-47-47-47-113t47-113q47-47 113-47t113 47q47 47 47 113t-47 113q-47 47-113 47t-113-47Zm169.5-56.5Q560-447 560-480t-23.5-56.5Q513-560 480-560t-56.5 23.5Q400-513 400-480t23.5 56.5Q447-400 480-400t56.5-23.5ZM480-480ZM200-120q-33 0-56.5-23.5T120-200v-160h80v160h160v80H200Zm400 0v-80h160v-160h80v160q0 33-23.5 56.5T760-120H600ZM120-600v-160q0-33 23.5-56.5T200-840h160v80H200v160h-80Zm640 0v-160H600v-80h160q33 0 56.5 23.5T840-760v160h-80Z"/>
</symbol>

2) Update the search form template

Info

Do this step only if you have overridden search-form.twig in the ShopUi module at the project level. If you have not overridden this template, skip to 3) Update the header template.

In src/Pyz/Yves/ShopUi/Theme/default/components/molecules/search-form/search-form.twig, add the ImageSearchAiWidget inside the search input area. Place it after the <input> element and before the submit button:


{% if data.byImage and widgetGlobalExists('ImageSearchAiWidget') %}
    {% widget 'ImageSearchAiWidget' with {
        data: {
            dataSearchId: attributes['data-search-id'],
        },
    } only %}{% endwidget %}
{% endif %}

3) Update the header template

Info

Do this step only if you have overridden header.twig in the ShopUi module at the project level. If you have not overridden this template, skip to 6) Apply the frontend changes.

In src/Pyz/Yves/ShopUi/Theme/default/components/organisms/header/header.twig, pass byImage: true in the data block when including the search form molecule:


{% include molecule('search-form', 'SearchPage') with {
    ...
    data: {
        byImage: true,
    },
} only %}

4) Add the project-level component files

Create the following project-level files to register and style the search-by-image component.

src/Pyz/Yves/AiCommerce/Theme/default/components/molecules/search-by-image/index.ts

import './search-by-image';
import register from 'ShopUi/app/registry';

export default register(
    'search-by-image',
    () =>
        import(
            /* webpackMode: "lazy" */
            /* webpackChunkName: "search-by-image" */
            'AiCommerce/components/molecules/search-by-image/search-by-image'
        ),
);

src/Pyz/Yves/AiCommerce/Theme/default/components/molecules/search-by-image/search-by-image.scss

@include ai-commerce-search-by-image {
    position: absolute;
    right: rem(40);
    top: 50%;
    translate: 0 -50%;
    z-index: $setting-zi-search-suggestions + 2;

    @include helper-breakpoint(lg) {
        right: rem(10);
    }

    &__popup-trigger {
        @include helper-effect-transition(rotate);
        border: none;
        width: rem(32);
        height: rem(32);
        background: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;

        &:hover {
            rotate: 90deg;
        }
    }
}

src/Pyz/Yves/AiCommerce/Theme/default/components/molecules/search-by-image/search-by-image.twig


{% extends molecule('search-by-image', '@SprykerFeature:AiCommerce') %}

{% block triggerFileButton %}
    {% set triggerButtonClassname = "search-by-image__popup-trigger search-by-image__popup-trigger--#{data.dataSearchId}" %}
    {{ parent() }}
{% endblock %}

{% block triggerPhotoButton %}
    {% set triggerButtonClassname = "search-by-image__popup-trigger search-by-image__popup-trigger--#{data.dataSearchId}" %}
    {{ parent() }}
{% endblock %}

5) Update TypeScript configuration

In tsconfig.yves.json, add the AiCommerce/* path alias to the compilerOptions.paths section:

"AiCommerce/*": ["./vendor/spryker-feature/ai-commerce/src/SprykerFeature/Yves/AiCommerce/Theme/default/*"]
Verification

Make sure the AiCommerce/* entry is added alongside the other module path aliases in the paths object.

6) Apply the frontend changes

Apply the frontend changes:

docker/sdk cli npm install
docker/sdk cli console frontend:project:install-dependencies
docker/sdk cli console frontend:yves:build
Verification

On the Storefront, make sure the camera icon is displayed next to the search bar. Click the icon, upload an image, and verify that you are redirected to either the search results page or the matching product detail page, depending on the configured redirect type.