> ## 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.

# SEO URLs and link optimization

> Define the structure of shop addresses, rescue old links via redirects and remove unnecessary parameters from the URL.

The address of a page is one of the few ranking factors that you determine entirely yourself. WEBSALE V8s works on three levels for this, each building on the previous one.

| Level | What it does |
| - | - |
| SEO URLs | determines how the addresses of the start page, categories, products and information pages are structured |
| Basic link optimization | redirects old calls with parameters to the matching SEO URL |
| Parameter removal | additionally removes individual, unneeded parameters from the address |

> [!NOTE]
>
> In V8s, SEO URLs are already activated and ready to use. Basic link optimization is switched on automatically along with them. This section mainly describes how to adjust the structure and how to convert an existing shop.

> [!WARNING]
>
> For the shop to be able to generate SEO URLs at all, each subshop must have its own domain. If this cannot be set up in exceptional cases, set the `AddShopAndSubshopIDInRobotCanonical` parameter in the `shop.config`.

Materials: URL parameters

## Global settings

These settings apply to all SEO URLs of a subshop and are located in the TopRank Manager under "URL settings".

| Setting | Meaning | Default |
| - | - | - |
| Term separator | separates words within a term | hyphen |
| Suffix separator | separates the URL from the counter that is appended for duplicates | hyphen |
| Force lowercase | converts the entire URL to lowercase | off |
| One URL per product | generates only one address per product instead of one per category path | off |

> [!NOTE]
>
> "One URL per product" is the most effective measure against duplicate content for products assigned to several categories. Without it, the same product gets its own address for each category path.

### Encoding of terms

The shop builds the descriptive parts of the URL from category and product names. If these contain spaces, umlauts or other special characters, they are encoded according to internet standards. Everything except `a` to `z`, `A` to `Z` and `0` to `9` is replaced.

The category "Broschüren" thus becomes `Brosch%fcren`. That is not readable. You define your own rules via the `LinkNameEncoding` section in the `shop.config`.

**Variant 1: resolve German umlauts.** Easy to read in any browser and usable for search engines.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<LinkNameEncoding>
   ä = ae
   Ä = Ae
   ö = oe
   Ö = Oe
   ü = ue
   Ü = Ue
   ß = ss
</LinkNameEncoding>
```

"Broschüren" thus becomes `Broschueren`.

**Variant 2: UTF-8 replacement characters.** Search engines and modern browsers display the umlaut.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<LinkNameEncoding>
   ä     = %C3%A4
   Ä     = %C3%84
   ö     = %C3%B6
   Ö     = %C3%96
   ü     = %C3%BC
   Ü     = %C3%9C
   ß     = %C3%9F
   $hash = %23
</LinkNameEncoding>
```

**Variant 3: remove characters.** With the replacement value `$delete`, a character disappears completely.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<LinkNameEncoding>
   * = $delete
</LinkNameEncoding>
```

The category `*S*i*l*b*e*r*` thus becomes `Silber`.

> [!WARNING]
>
> The hash character must be written as `$hash`, otherwise it is read as the start of a comment and the line disappears.

> [!WARNING]
>
> Spaces cannot be reconfigured. They always become a hyphen, which is a valid separator for search engines.

> [!NOTE]
>
> You only need to define the characters that are to be handled differently. For each language, these are usually only a handful.

Reference: LinkNameEncoding section

## The structure per page type

### Start page

The start page is called without any parameters, solely via the main domain of the subshop.

### Categories and products

Both are configured in the TopRank Manager, and both use the same tag `SEO-Cat()` for the category path. The only difference is that the product URL additionally appends `SEO-PR-Name`.

| Page type | Default | Result |
| - | - | - |
| Category | `~SEO-Cat(0,1,/,n)~` | `www.shop.de/Kurzarm` |
| Product | `~SEO-PR-Name~` | `www.shop.de/Seidenbluse` |

The `SEO-Cat()` tag takes four values: how many levels from the top, how many from the bottom, the separator and the direction.

This product menu serves as an example to work through. The customer is in "Kurzarm", and the opened product is called "Seidenbluse".

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
Damen                    (Ebene 1)
  Oberbekleidung         (Ebene 2)
    Adidas               (Ebene 3)
      Blusen             (Ebene 4)
        Kurzarm          (Ebene 5)
```

| Tag setting | Category URL |
| - | - |
| `~SEO-Cat(0,1,/,n)~` | `/Kurzarm` |
| `~SEO-Cat(1,1,/,n)~` | `/Damen/Kurzarm` |
| `~SEO-Cat(0,2,/,n)~` | `/Blusen/Kurzarm` |
| `~SEO-Cat(1,3,/,n)~` | `/Damen/Adidas/Blusen/Kurzarm` |
| `~SEO-Cat(1,3,/,r)~` | `/Kurzarm/Blusen/Adidas/Damen` |

For products, the same tag is placed in front of the product name:

| Tag setting | Product URL |
| - | - |
| `~SEO-PR-Name~` | `/Seidenbluse` |
| `~SEO-Cat(1,0,/,n)~/~SEO-PR-Name~` | `/Damen/Seidenbluse` |
| `~SEO-Cat(1,2,/,n)~/~SEO-PR-Name~` | `/Damen/Blusen/Kurzarm/Seidenbluse` |

> [!NOTE]
>
> The fourth parameter controls the direction: `n` for the usual top-to-bottom order, `r` for the reverse.

> [!NOTE]
>
> If the values for top and bottom overlap, duplicate levels appear in the path. The shop detects and removes them. A theoretical `/Damen/Oberbekleidung/Adidas/Oberbekleidung/Adidas/Blusen/Kurzarm` becomes `/Damen/Oberbekleidung/Adidas/Blusen/Kurzarm`.

Instead of the names, you can store your own terms: for categories in the TopRank Manager under "Terms for building the URL", for products via the SEO content for products feature.

> [!WARNING]
>
> First enter all category terms completely and then put them live together. To do this, first set the `UseSeoNameForCategoryLink-Allow` parameter in the `TopRank` section to `no` and only set it to `yes` after maintenance is complete. Otherwise the addresses change bit by bit, and every change costs a redirect.

Reference: SEO-Cat · SEO-PR-Name

Guide: SEO content for products

### Information pages

Static pages such as the legal notice or contact page have no data from which a term could be built. Without intervention, the shop delivers an address with parameters here. In the TopRank Manager under "URLs of information pages", you store the desired terms for each page.

Whether an information page appears there at all depends on two rules:

| Situation | Provision |
| - | - |
| File name starts with `tpl_` **and** is located in `benutzer/templates/<Subshop-ID>` | automatic |
| File name starts with `tpl_` but is located elsewhere | provide once in the TopRank Manager |
| File name without `tpl_` | always provide in the TopRank Manager |

> [!NOTE]
>
> Both rules are already met in the delivery state of a new shop. If you stick to them, new information pages appear in the TopRank Manager automatically.

### Checkout and customer account

These pages are not accessible to search engines and are therefore irrelevant for SEO. They keep addresses with technical control parameters.

## Duplicate addresses

Each SEO URL may only point to one target. If the scheme results in the same address for two targets, the shop appends a counter to the second one.

With two categories "Damen", one under "Oberbekleidung" and one under "Hosen", the result is:

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
www.shop.de/damen       (unter Oberbekleidung, zuerst gebildet)
www.shop.de/damen-1     (unter Hosen)
```

> [!NOTE]
>
> The shop generates the addresses one after the other. Whoever comes first keeps the address without a counter. If it matters to you which of the two categories gets the clean address, assign your own terms to the other one.

> [!NOTE]
>
> When you enter your own terms for products, categories and information pages, the shop immediately reports if a term is already in use. Saving is then not possible.

## Basic link optimization

It ensures that a call with an old V8 link is automatically redirected via 301 to the matching SEO URL. This preserves the link equity of the old addresses.

It applies in all three cases in which different addresses circulate for the same target:

* different order of parameters
* renamed products or categories
* incorrectly created or mistyped links

### Setup

The `LinkOptimization` section belongs **inside** `TopRank`.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<TopRank>
   ...
   <LinkOptimization>
      Allow = test
   </LinkOptimization>
   ...
</TopRank>
```

| Value | Effect |
| - | - |
| `test` | only takes effect in test mode |
| `yes` | takes effect in production |
| `no` | off |

### Testing

As an indicator in the shop, a bracket that only applies when optimization is active is helpful:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ST-LinkOptimization}
   Link-Optimierung ist aktiv.
{/ST-LinkOptimization}
```

Call the shop with the test parameters and then enter a product URL in the old scheme. When you confirm, the address must turn into the SEO URL by itself.

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
https://www.ihr-shop.de/?test=on&linkoptimization-test=on
https://www.ihr-shop.de/?websale8=meine_shop_id&pi=abc&ci=123
```

You can end the test mode with `&linkoptimization-test=off`.

Reference: TopRank section · ST-LinkOptimization

Guide: Switching the shop's test modes on/off

## Removing parameters from the URL

Referer parameters are indispensable for measuring advertising success and harmful for search engines, because they make the same content accessible under multiple addresses. Parameter removal solves this: the shop takes the parameter into the session and resets the address to the short version via 301.

> [!NOTE]
>
> The values are retained in the process. Via `WS-Referer` and `WS-SubReferer`, you pass them on to your tracking system without them appearing in the address. For the server variable, there is `WS-HTTPReferer`.

### Requirement and scope

Parameter removal only works when basic link optimization is active and only on three pages: the start page, the product overview and the product detail view. All other pages keep their parameters.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<TopRank>
   ...
   <LinkOptimization>
      Allow = yes

      <RemovableStartPageParameters>
         +Entry = ref
      </RemovableStartPageParameters>

      <RemovableCategoryPageParameters>
         +Entry = ref
         +Entry = subref
      </RemovableCategoryPageParameters>

      <RemovableProductPageParameters>
         +Entry = ref
      </RemovableProductPageParameters>
   </LinkOptimization>
   ...
</TopRank>
```

> [!NOTE]
>
> Use a separate `+Entry` line for each parameter, with the name in lowercase.

> [!WARNING]
>
> Not every parameter may be removed. Some control shop functions, and without them the call no longer works. Check each parameter individually before entering it.

> [!NOTE]
>
> Each redirect counts like a click and appears in the statistics. For a campaign with many calls, this skews the numbers.

For testing, a made-up referer is sufficient, for example `https://www.ihr-shop.de/Beispielprodukt?ref=test`. The parameter must disappear after confirming. Repeat the test for each page type you have configured.

Reference: WS-Referer · WS-SubReferer · WS-HTTPReferer

Materials: Which parameters may be removed? · Parameter removal with URL-based tracking systems

## Redirects for old and missing addresses

In addition to basic link optimization, the shop also redirects when an address leads nowhere. This avoids the 404 page, which is unfavorable from an SEO perspective.

| Case | Target |
| - | - |
| outdated link name, for example after renaming | the current address |
| address never existed | start page or catch page |
| template called via `&tpl=` that no longer exists | start page or catch page |
| product without replacement product and without available category | start page or catch page |
| category without available next higher category | start page or catch page |

### Defining the status code

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<TopRank>
   ...
   SEO-URLs-InvalidURLWithoutRedirectInformation = 301
   ...
</TopRank>
```

Permitted values are `301`, `401` and `404`. If nothing is specified, 301 applies.

> [!NOTE]
>
> The parameter only applies to addresses that never existed or for which no redirect information is available. The handling of products and categories that are no longer available is not affected.

> [!NOTE]
>
> If you set it to 404 but need an exception for individual addresses, WEBSALE system administration sets up these redirects on the server.

Guide: Products and categories that are no longer available

## Content from third-party systems: ContentControl

If content is integrated via `WS-ExternInclude()` or via the JSON interface and has disappeared there, the shop still delivers status code 200. After all, the template exists. To search engines, this looks like a valid page without content.

ContentControl allows you to modify the HTTP header and output after the fact. Because this is not standard behavior, the affected templates must be entered explicitly.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ContentControlLoadTemplates>
   +Entry = tpl_cms.htm
</ContentControlLoadTemplates>
```

> [!WARNING]
>
> This does not work for standard templates from the `Templates` section. The information pages must be entered here and called via `WS-LoadTpl()` or `WS-SSLLoadTpl()`.

The following tags are then available on the template:

| Tag | Effect |
| - | - |
| `ContentControl-SetHeader_Status()` | sets the HTTP status code |
| `ContentControl-SetHeader_Location()` | sets the target address of a redirect |
| `ContentControl-SuppressResponseBody` | suppresses the output, useful for a redirect |
| `WS-ContentControl-UseAsExclusiveResponseBody` | replaces the output completely |
| `ST-ContentControl` | bracket, only applies where the method is available |

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ST-ContentControl}
   ~ContentControl-SetHeader_Status(404 Not found)~
   <WS-ContentControl-UseAsExclusiveResponseBody>
      <html>
         <head></head>
         <body>Diese Seite gibt es nicht mehr.</body>
      </html>
   </WS-ContentControl-UseAsExclusiveResponseBody>
{/ST-ContentControl}
```

> [!NOTE]
>
> Specify the status code in full, that is, with text, as the standard requires. `404 Not found` instead of just `404`.

> [!NOTE]
>
> This refers to the HTTP header, not the `head` area of the template. The adjustments affect the protocol between server and browser.

Reference: ContentControlLoadTemplates section · ContentControl-SetHeader\_Status() · ContentControl-SetHeader\_Location · ContentControl-SuppressResponseBody · WS-ContentControl-UseAsExclusiveResponseBody · ST-ContentControl

## Search links for Google Ads

An ad link can point directly to the internal search instead of to a product. There is one pitfall: Google encodes the search term in UTF-8, while the shop expects it in the ISO code of the subshop. A term with an umlaut therefore returns nothing.

Append the parameter `&search_input_code=utf-8` to every such link.

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
https://www.ihr-shop.de/?act=search&search_input=Einmalkan%C3%BClen&search_input_code=utf-8
```

The shop then converts `%C3%BC` into "ü" and finds "Einmalkanülen".

## Converting an existing shop

Converting from V8 links to SEO URLs requires server-side activations, and the SEO URLs must also be enabled for the import. Please contact your WEBSALE representative for this.

> [!WARNING]
>
> Clarify two things before the technical setup:
>
> * If you integrate external content via a proxy, for example a WordPress installation under `/magazin/`, this call must be set up as an exception on the WEBSALE proxies.
> * If you deliver static content from self-created subweb folders, the index file must be named exactly `index.htm`, not `index.html`.

### Step 1: Configure addresses in the TopRank Manager

Promptly after activation, define how the addresses for categories, products and information pages should be structured.

### Step 2: Optimize product names (optional)

If you want to revise the product URLs anyway, do it now. This saves you a second round of redirects.

To do this, first set `Link-Allow` to `no`, change the names, and only set it to `yes` when the SEO URLs go live.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<SEOProductFields>
   Link-Allow = no
</SEOProductFields>
```

If the maintained SEO content should only apply to the SEO URLs during the conversion phase and not to the previous V8 link generation, a second parameter controls this. It only affects product links of the old link logic and has no meaning after going live.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<SEOProductFields>
   Link-Allow       = yes
   LegacyLink-Allow = test
</SEOProductFields>
```

| Value of `LegacyLink-Allow` | Effect on the old link logic |
| - | - |
| `no` | the SEO content is not taken into account there |
| `test` | it only takes effect in the shop's test mode |
| `yes` | it also takes effect in production |

> [!NOTE]
>
> `Link-Allow` must be set to `yes` for this.

> [!WARNING]
>
> The value `test` currently probably does not behave as described. Check the result in the shop before relying on it, and if in doubt, use `no` or `yes` instead.

### Step 3: Activate test mode

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<TopRank>
   ...
   SEO-URLs-Allow = test
   ...
</TopRank>
```

Again, a bracket helps as an indicator in the shop:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{ST-SEOURLsTest}
   SEO-URL-Testmodus ist aktiv.
{/ST-SEOURLsTest}
```

### Step 4: Adjust parameters on link tags

This is the most time-consuming step. In V8, every address began with `?websale8=`, so additional parameters always came with `&`. With SEO URLs, this first parameter is dropped for all pages relevant to search engines. Whether an additional parameter must now be appended with `?` or with `&` can no longer be determined in advance.

Therefore, place the `WS-EnsureNextLinkContainsURLParams` tag in front of every link tag to which you append a parameter or an anchor. After that, `&` applies consistently again.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~WS-EnsureNextLinkContainsURLParams~~PR-Link~&parameter1=wert
~WS-EnsureNextLinkContainsURLParams~~CAT-Link~&parameter1=wert
~WS-EnsureNextLinkContainsURLParams~~WS-LoadTpl(tpl_agb.htm)~&parameter1=wert
~WS-EnsureNextLinkContainsURLParams~~WS-LoadTpl(tpl_agb.htm)~#ende
```

> [!WARNING]
>
> Search all templates **and** the text maintenance platform for `~&` and `~#`. Each of these places needs the adjustment. An overlooked place creates a broken link that only becomes noticeable in live operation.

Two special cases need the same tag: the paging link for Factfinder results and the product links from econda Cross Sell.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~WS-EnsureNextLinkContainsURLParams~~E-Search_PagingLink~
```

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{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$)}
```

### Step 5: Update the JavaScript library

With the new address structure, the WEBSALE AJAX functions require at least version 1.8.4, regardless of whether you use the system library, the core library or WS modules.

### Step 6: Transfer short addresses for campaigns

With SEO URLs active, the short addresses for print campaigns move to the TopRank Manager. From this point on, the previous separate service no longer has any effect.

> [!WARNING]
>
> Transfer your short addresses to the TopRank Manager manually. Addresses that are not transferred remain visible in the old service but are no longer taken into account by the shop. This only becomes noticeable when a print ad leads nowhere.

> [!NOTE]
>
> Subshops without active SEO URLs and V7 shops continue to use the old service. A transition is therefore possible.

### Step 7: Testing

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
https://www.ihr-shop.de/?websale8=mustershop&pi=4-5749&ci=1-5749&test=on&seo-urls-test=on
```

Check whether the addresses match what you have configured and whether all link tags work.

### Step 8: Go live

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<TopRank>
   ...
   SEO-URLs-Allow = yes
   ...
</TopRank>
```

> [!NOTE]
>
> This also switches on basic link optimization. From this moment on, all old links are automatically redirected to the new ones.

Reference: SEOProductFields section · ST-SEOURLsTest · WS-EnsureNextLinkContainsURLParams

Materials: WEBSALE JavaScript library

## Related topics

* Guide: SEO content for products
* Guide: Generating a canonical instruction in the head
* Guide: SEO optimization with TopRank
* Guide: Products and categories that are no longer available


## Related topics

- [Link shortener](https://dokumentation.websale.de/en/v8s/funktionen-zur-shop-optimierung/link-shortener.md)
- [SEO optimization with TopRank](https://dokumentation.websale.de/en/v8s/seo/seo-optimierung-mit-toprank.md)
- [SEO content for products](https://dokumentation.websale.de/en/v8s/seo/seo-content-fuer-produkte.md)
- [Products and categories that are no longer available](https://dokumentation.websale.de/en/v8s/seo/nicht-mehr-verfuegbare-produkte-und-kategorien.md)
- [Structured data and rich snippets](https://dokumentation.websale.de/en/v8s/seo/strukturierte-daten-rich-snippets.md)


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