# SEO redirects (https://docs.salla.dev/twilight/react/routes/seo-redirects)



<Callout title="Framework: TanStack Start">
  This page is written for TanStack Start, the default and currently supported framework. [See what depends on the framework](https://docs.salla.dev/twilight/react/start/frameworks).
</Callout>

Links outlive routes. Customers keep old bookmarks, emails and shared links, and search engines keep old URLs indexed. When a route is deprecated or renamed, a link that lands on a 404 loses that customer and the page's ranking. The engine keeps a few routes only to send those visitors to the current page, so nothing breaks when the storefront's URLs change.

Read this page to see which URLs are redirected, and to add or change a redirect in your theme.

<Callout type="info" title="Keep a redirect when you retire a URL">
  If your theme drops or renames a route, add a redirect from the old path instead of deleting it. See [Change or add a redirect](#change-or-add-a-redirect).
</Callout>

## Redirect routes [#redirect-routes]

The brand redirect and `/logout` are route files the engine generates into your theme's `app/routes/`. The engine serves the others from its own `.twilight/` folder, so your theme has no file for them. Their loaders live in `@salla.sa/twilight-theme-engine/routes/seo-redirects`.

| From                                                            | To                                           | How                                                                                                                                                       |
| --------------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/$slug/brand-{$id}`                                            | `/{locale}/brands/{id}`                      | `slugBrandRedirectLoader` throws a redirect.                                                                                                              |
| `/pending-orders`                                               | `/{locale}/account/orders?status=pending`    | `pendingOrdersRedirectLoader` throws a redirect. See [Pending orders](https://docs.salla.dev/twilight/react/routes/pending-orders).                                                            |
| `/account/pending_orders`                                       | the same                                     | The same loader. The Salla user menu links here.                                                                                                          |
| `/logout`                                                       | the store home                               | The `LogoutRedirect` component. See [Logout](https://docs.salla.dev/twilight/react/routes/logout).                                                                                             |
| `/account/rating`                                               | `/{locale}/account/orders`                   | `ratingRedirectLoader`. The loyalty "rate your orders" link points here.                                                                                  |
| `/profile`, `/orders`, `/wishlist`, `/wallet`, `/notifications` | the same name under `/account`               | `accountRedirectLoader` throws a 301 and keeps the query string. These are the deprecated short forms, and old links from other storefronts keep working. |
| `/latest-products`, `/most-sales-products`, `/offers`           | `/products?source=latest`, `sales`, `offers` | `productsSourceRedirectLoader` throws a 301 and keeps the rest of the query string. These are Twig's listing addresses. See [Products](https://docs.salla.dev/twilight/react/routes/products). |

`{locale}` is the language in the visited URL, or `ar` when the URL had none. The five account shortcuts and the three listing addresses keep a missing language missing instead. Each route also exists with a language prefix, like every storefront path.

The generated file for the brand redirect shows the pattern. The others are the same shape:

```tsx title="app/routes/$slug.brand-$id.tsx"
// @auto-generated
import { createFileRoute } from '@tanstack/react-router';
import { slugBrandRedirectLoader } from '@salla.sa/twilight-theme-engine/routes/seo-redirects';

export const Route = createFileRoute('/{-$locale}/$slug/brand-{$id}')({
  loader: ({ params }) =>
    slugBrandRedirectLoader({
      params: { slug: params.slug, id: params.id, locale: params.locale },
    }),
});
```

## Product short links [#product-short-links]

A short link such as `/ar/lvXvzln` matches no route, so the router shows the [not-found page](https://docs.salla.dev/twilight/react/routes/not-found). Before showing a 404, that page tries the code as a product:

1. The path must be one segment, or a language plus one segment, and the code must be 5 to 10 letters or digits and not a language code. Anything else is a normal 404.
2. While the lookup runs, the page renders nothing, so the 404 does not flash.
3. The code is sent to the products API as if it were a product id.
4. On a hit, the browser navigates (replacing the history entry) to `/{locale}/{slug}/p{id}`, with the slug taken from the product's `url`.
5. On a miss or a failed request, the 404 shows.

This happens in the browser only. A crawler that does not run JavaScript sees the 404.

## Change or add a redirect [#change-or-add-a-redirect]

The engine has no redirect table. A redirect is a route whose loader throws one.

* **Change a target.** Write your own loader with `redirect` from `@tanstack/react-router` in a file of the same name: take over the generated brand or logout file by deleting `// @auto-generated`, or, for a redirect the engine serves, add the file (for example `app/routes/offers.tsx`) to `app/routes/` without that line.
* **Add a redirect.** Declare the old path in `app/routes.ts` and throw from its loader:

```ts title="app/routes.ts"
import { route } from '@tanstack/virtual-file-routes';

export const routes = [route('/old-sale', 'old-sale.tsx')];
```

```tsx title="app/routes/old-sale.tsx"
import { createFileRoute, redirect } from '@tanstack/react-router';

export const Route = createFileRoute('/{-$locale}/old-sale')({
  loader: ({ params }) => {
    throw redirect({ to: `/${params.locale ?? 'ar'}/products`, search: { source: 'offers' }, replace: true });
  },
});
```

See [Add a custom route](https://docs.salla.dev/twilight/react/routes/add-a-custom-route) for how route files and `app/routes.ts` fit together.

## Edge cases [#edge-cases]

* **Slugs are not canonicalised.** `/wrong-slug/p123` still renders the product, and `/wrong-slug/brand-77` still redirects. Canonical tags, not redirects, keep search engines on one URL.
* **Query strings are dropped** by the brand redirect. The account and listing redirects keep them.
* **Language rules still apply.** The locale layout redirects a bare path to `/ar/...` on multilingual stores, and removes the prefix on single-language stores.

## See also [#see-also]

* [Not-found page](https://docs.salla.dev/twilight/react/routes/not-found)
* [Brand products](https://docs.salla.dev/twilight/react/routes/brand-products) and [Product page](https://docs.salla.dev/twilight/react/routes/product)
* [Overview](https://docs.salla.dev/twilight/react/routes) and [Routes and pages](https://docs.salla.dev/twilight/react/guide/routes-and-pages)
