> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# econda Cross Sell

> Integrate personalized product recommendations from econda on the home page, category, product and basket pages, including fallback display and slider.

> [!WARNING]
>
> Under current case law, tracking, cookies and comparable advertising effectiveness research tools may only transfer data once the visitor has actively consented. A notice is not sufficient, and pre-ticked checkboxes are not permitted. Clarify the implementation with your data protection officer before carrying out any of the following steps.

econda Cross Sell shows visitors product recommendations based on the behavior of all visitors and on their own profile. Because the display runs via a shop template, the recommended products look exactly the same as everywhere else in the shop, and a design change takes effect in both places.

Four pages are supported:

* Shop home page `ws_start.htm`
* Product overview page `ws_category.htm`
* Product detail view `ws_product.htm`
* Basket page `ws_basket.htm`

## How it works together

The process is the same on all four pages:

1. An econda widget requests recommendations and receives a product list.
2. A callback function converts this list into shop parameters.
3. The shop loads its own template via AJAX, which displays these products using shop tags.
4. The content is placed in a prepared area of the page.

The only difference is which context the widget receives, i.e. whether it knows the current category, the current product or the basket contents.

## Two approaches

| | without tracking interface (recommended) | with tracking interface |
| - | - | - |
| Activation by WEBSALE | none | tracking interface and Dataflow Manager |
| Data feed | clarified via econda | WEBSALE creates it in the Dataflow Manager |
| Files to include | `ws-module-cs-links-1.8.5.js`, `econda-recommendations-design.js`, `econda-recommendations-3.0.11.js` | WEBSALE system library, design component, `econda-recommendations-3.0.20.min.js` |
| Script wrapping | in `window.econda.ready(() => { ... });` | without this wrapping |

Everything else is the same. The following instructions describe the recommended approach; the differences are noted where applicable.

## Preparation

After placing the order, you receive an account ID and one or more widget IDs from econda. Share these with WEBSALE.

Technically, you could start right after that. It makes more sense to first clarify what the widgets should return, because this determines which context you pass.

| Placement | What should be recommended | Fallback if nothing fits |
| - | - | - |
| Home page | for a recognized visitor, products from their profile, for example recently viewed and not purchased, plus matching recommendations | top sellers and new products of the shop |
| Category page | products from the profile, limited to the same category | top sellers and new products of the category |
| Product detail view | in addition to the selected product, further products from the profile | top sellers of the category, then of the shop |
| Basket | products that other customers bought in addition | predefined list of add-on products in the lower price range |

> [!NOTE]
>
> On the home page, category page and product page, requests are additionally made with profile identifiers, i.e. visitor, customer, user or recipient ID, provided the visitor is recognized. When this should happen is the most important question when setting up the widgets. How the recommendations are generated from this is configured in the econda interface.

## Setup

### Step 1: Include JavaScript files

Without tracking interface:

| File | Source |
| - | - |
| `ws-module-cs-links-1.8.5.js` | must be created by the designer |
| `econda-recommendations-design.js` | available globally |
| `econda-recommendations-3.0.11.js` | from econda; if not supplied, from the econda backend |

With tracking interface, instead:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<head>
   <script type="text/javascript" src="/$WS/ws_sysdata/js/ws-system-1.8.3.js"></script>
   <script type="text/javascript" src="../ihr-verzeichnis/ws-design-1.8.3.js"></script>
   <script type="text/javascript" src="/$WS/ws_sysdata/js/econda-recommendations-3.0.20.min.js"></script>
</head>
```

Materials: WEBSALE JavaScript library

### Step 2: Add functions to the design component

Four functions are called at fixed points. They may remain empty but must exist. Use them to build loading indicators, messages and animations.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
// vor dem Absetzen der AJAX-Anfrage, beispielsweise für eine Ladeanzeige
function ws_AJAXloadEcondaStart() {}

// wenn die AJAX-Verbindung selbst fehlschlug
function ws_AJAXloadEcondaError() {}

// wenn Cross-Sell-Produkte geladen werden konnten
function ws_AJAXloadEcondaResponseSuccess() {}

// wenn keine Cross-Sell-Produkte geladen werden konnten
function ws_AJAXloadEcondaResponseError() {}
```

### Step 3: Define the display area

An HTML element with an ID marks the position where the recommendations appear. It remains empty; the content is inserted later via AJAX.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<div id="econda-cross-sell"></div>
```

> [!WARNING]
>
> If you show several widgets on one page, each needs its own area with its own ID and its own template. Otherwise, the second response overwrites the content of the first.

### Step 4: Include the JavaScript

It is recommended to include it below the display area in the `<body>`.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<div id="econda-cross-sell"></div>

<script type="text/javascript">
window.econda.ready(() => {

   function econda_callback(targetElement, data, templateName) {
      if (data.products.length == 0)
         return;

      var payload = ws_getEcondaPayload(data.products);

      ws_AJAXloadTemplatePOST('~WS-AJAXLoadTpl(incl_econda_cross_sell.htm)~', '~WS-Charset~',
         ws_AJAXloadEcondaStart, ws_AJAXloadEcondaError,
         'ws_AJAXloadEcondaResponseSuccess()', 'ws_AJAXloadEcondaResponseError()', payload);
   }

   var widget = new econda.recengine.Widget({
      renderer: {
         type: 'websale',
         callback: econda_callback
      },
      accountId: 'Ihre Account ID',
      id: Ihre Widget ID,
      context: {
      }
   });

   widget.render();

});
</script>
```

> [!NOTE]
>
> With the tracking interface, the outer wrapping `window.econda.ready(() => { ... });` is omitted; the content remains the same.

> [!NOTE]
>
> You can also place the script in the `<head>` section. In that case, the call must wait until the page has loaded:
>
> ```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> $(document).ready(function() {
>    widget.render();
> });
> ```

#### The context per page

Only this one part differs between the four pages.

Home page, without context:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
context: {
}
```

Product overview page, with the category path:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
context: {
   categories: {
      type: 'productcategory',
      path: '~CAT-JSPath~'
   }
}
```

Product detail view, with category path and product:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
context: {
   products: [{id: '~PR-ProdIndex~'}],
   categories: {
      type: 'productcategory',
      path: '~CAT-JSPath~'
   }
}
```

Basket page, with all products in the basket:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
context: {
   products: [{BASKET-PR-Data}~DC-Int1_set(0)~{@BASKET-PR-Data}~DC-Int1_inc~{!DC-Int1(1)},{/!DC-Int1(1)}{id: '~BASKET-PR-ProdIndex~'}{/@BASKET-PR-Data}{/BASKET-PR-Data}]
}
```

> [!NOTE]
>
> The counter places the comma between the entries, but not before the first one. Without it, the list would not be valid JavaScript.

### Step 5: Create the widget template

Create a template with the name specified in `WS-AJAXLoadTpl()`. It must contain an AJAX area whose name carries the ID from step 3.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<WS-Ajax-econda-cross-sell>
   {WS-PRListFromLoadTplLink_data}
      {@WS-PRListFromLoadTplLink_data}
         {PR-LoadData($WS-PRListFromLoadTplLink_id$,$WS-PRListFromLoadTplLink_type$)}
            <a href="~WS-EnsureNextLinkContainsURLParams~~PR-Link~~WS-PRListFromLoadTplLink_addlink~">~PR-Name~</a>
         {/PR-LoadData($WS-PRListFromLoadTplLink_id$,$WS-PRListFromLoadTplLink_type$)}
      {/@WS-PRListFromLoadTplLink_data}
   {/WS-PRListFromLoadTplLink_data}
</WS-Ajax-econda-cross-sell>
```

Within the `PR-LoadData()` wrapper, all the usual product tags are available. This gives you complete freedom in the design.

> [!NOTE]
>
> `WS-EnsureNextLinkContainsURLParams` ensures that the appended parameter starts with the correct separator. With SEO URLs, this cannot be predicted.

> [!NOTE]
>
> If econda returns no products, the display area remains empty. How to show something else instead is described further below.

Reference: PR-LoadData() · WS-Ajax-"ID" · WS-AJAXLoadTpl() · WS-EnsureNextLinkContainsURLParams · WS-PRListFromLoadTplLink\_addlink · WS-PRListFromLoadTplLink\_data · WS-PRListFromLoadTplLink\_id · WS-PRListFromLoadTplLink\_type

## The JavaScript in detail

The code consists of two blocks: the callback function and the widget.

| Location | Meaning |
| - | - |
| `ws_getEcondaPayload(data.products)` | generates the parameters for the shop from the econda response. The function is part of the WEBSALE JavaScript library |
| `if (data.products.length == 0) return;` | aborts if econda returned nothing, saving the unnecessary call to the shop |
| `~WS-AJAXLoadTpl(...)~` | the template used to display the recommendations |
| `type: 'websale'` | must always be set like this |
| `callback` | the name of the callback function from the first block |
| `accountId` and `id` | account ID and widget ID from econda |
| `context` | the context, see step 4 |

> [!NOTE]
>
> For several widgets on one page, the second block is repeated, each with its own callback function and its own template. If you exceptionally use the same template, the name of the AJAX area in it must be changed per widget, for example via a one-time parameter.

> [!NOTE]
>
> In the econda control panel, you define what kind of data a widget returns, for example top sellers or "bought together". The decision about which widget appears on which page is therefore made there and not in the template.

## Adding a fallback display

If econda returns nothing, the position remains empty in the default state. Instead of the gap, something else can be shown, for example the shop's cross links.

### Step 1: Adjust the JavaScript

Two changes: the abort is removed so that the template is loaded even without econda data. And a one-time parameter is appended to the tag, passing the current product index to the template.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<script type="text/javascript">
window.econda.ready(() => {

   function econda_callback(targetElement, data, templateName) {
      var payload = ws_getEcondaPayload(data.products);

      ws_AJAXloadTemplatePOST('~WS-AJAXLoadTpl(incl_econda_cross_sell.htm)~&otp1=~PR-ProdIndex~', '~WS-Charset~',
         ws_AJAXloadEcondaStart, ws_AJAXloadEcondaError,
         'ws_AJAXloadEcondaResponseSuccess()', 'ws_AJAXloadEcondaResponseError()', payload);
   }

   ...

});
</script>
```

### Step 2: Adjust the widget template

The positive wrapper shows the econda recommendations, the negative one the fallback.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<WS-Ajax-econda-cross-sell>

   <!-- Empfehlungen von econda -->
   {WS-PRListFromLoadTplLink_data}
      {@WS-PRListFromLoadTplLink_data}
         {PR-LoadData($WS-PRListFromLoadTplLink_id$,$WS-PRListFromLoadTplLink_type$)}
            <a href="~WS-EnsureNextLinkContainsURLParams~~PR-Link~~WS-PRListFromLoadTplLink_addlink~">~PR-Name~</a>
         {/PR-LoadData($WS-PRListFromLoadTplLink_id$,$WS-PRListFromLoadTplLink_type$)}
      {/@WS-PRListFromLoadTplLink_data}
   {/WS-PRListFromLoadTplLink_data}

   <!-- Ersatz: die Cross Links des Shops -->
   {!WS-PRListFromLoadTplLink_data}
      {PR-LoadData($WS-OTP1$,0)}
         {Cat-AdvData($CS-Links,999)}
            {@PR-Data}
               <a href="~PR-Link~">~PR-Name~</a>
            {/@PR-Data}
         {/Cat-AdvData($CS-Links,999)}
      {/PR-LoadData($WS-OTP1$,0)}
   {/!WS-PRListFromLoadTplLink_data}

</WS-Ajax-econda-cross-sell>
```

> [!NOTE]
>
> The one-time parameter from step 1 is the reason the template knows which product is involved in the fallback case at all. Without it, there is no basis for the cross links.

> [!WARNING]
>
> With the fallback display, an AJAX call to the shop is made on every page view, even if econda returns nothing. This is the price for the position never remaining empty.

Reference: WS-OTPX() · Cat-AdvData()

## Showing recommendations in a slider

With many recommendations, a slider is clearer. The integration works as described above; only the animation call belongs in the function that is called after successful loading. Only then are the products in the display area.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
function ws_AJAXloadEcondaResponseSuccess() {
   $('#mycarousel_horizontal_econda').slick({
      dots: false,
      arrows: true,
      infinite: false,
      speed: 300,
      slidesToShow: 6,
      slidesToScroll: 6,
      responsive: [
         { breakpoint: 1200, settings: { slidesToShow: 4, slidesToScroll: 4 } },
         { breakpoint: 992,  settings: { slidesToShow: 3, slidesToScroll: 3 } },
         { breakpoint: 660,  settings: { slidesToShow: 2, slidesToScroll: 2 } },
         { breakpoint: 480,  settings: { slidesToShow: 1, slidesToScroll: 1 } }
      ]
   });
}
```

> [!WARNING]
>
> Do not call the animation when the page loads. At that point, the display area is still empty, and the slider would have nothing to show.

## Switching from "with interface" to "without interface"

The procedure is the same as for tracking: the old integration keeps running, the new one is built alongside it in design test mode and only swapped in after a successful test.

1. Have WEBSALE activate free positioning of the tracking interface.
2. Move the content of `ws_analyse.js` to a separate file and remove it from `ws_analyse.js`.
3. Include this file together with `WS-ExternalStatistics` in `{!ST-DesignTest}` on all pages.
4. Build the new integration in `ST-DesignTest`.
5. Check in design test mode.
6. Remove the wrappers and clean up the old integration.

Guide: Integration of econda

## Related topics

* Guide: Integration of econda
* Guide: Accessory products (Cross Links)
* Guide: How WEBSALE AJAX integrations work
* Guide: Consent to data processing (cookies)


## Related topics

- [Integration of econda](https://dokumentation.websale.de/en/v8s/integration-von-econda/integration-von-econda.md)
- [Troubleshooting notes](https://dokumentation.websale.de/en/v8s/fehlerbehebung.md)
- [WEBSALE JavaScript library](https://dokumentation.websale.de/en/v8s/materialien/websale-javascript-bibliothek.md)
- [SEO URLs and link optimization](https://dokumentation.websale.de/en/v8s/seo/seo-urls-und-link-optimierung.md)
- [JavaScript and jQuery](https://dokumentation.websale.de/en/v8s/templates/javascript-und-jquery.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.