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

# Redirects

> Send visitors from an old URL to a new one so old links keep working.

export const TryPromptButton = ({prompt, imageSrc, imageAlt = "Template preview", imageStyles = {}, buttonCta = "Build in Replo"}) => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const PUBLISHER_API_BASE_URL = "https://publisher.replo.app";
  const APP_URL = "https://dashboard.replo.app";
  const LoaderIcon = <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    animation: "spin 1s linear infinite"
  }}>
      <path d="M21 12a9 9 0 1 1-6.219-8.56" />
    </svg>;
  const ChevronIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="m9 18 6-6-6-6" />
    </svg>;
  async function postJSON(url, body, headers = {}, timeoutMs = 120000) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...headers
        },
        body: JSON.stringify(body ?? ({})),
        signal: controller.signal
      });
      const responseText = await response.text();
      if (!response.ok) throw new Error(`API Error: ${response.status}`);
      return responseText ? JSON.parse(responseText) : {};
    } finally {
      clearTimeout(timeoutId);
    }
  }
  async function handleTryPrompt(event) {
    event.preventDefault();
    event.stopPropagation();
    setIsLoading(true);
    setError(null);
    try {
      const body = {
        prompt,
        file: null
      };
      const {seed} = await postJSON(`${PUBLISHER_API_BASE_URL}/api/v1/marketing/issue-marketing-site-jwt`, body);
      if (!seed) throw new Error("No seed returned from API");
      const url = new URL(APP_URL);
      url.searchParams.set("type", "agent");
      url.hash = `seed=${encodeURIComponent(seed)}`;
      window.open(url.toString(), "_blank");
    } catch (caughtError) {
      console.error("Failed to generate prompt:", caughtError);
      setError("Something went wrong. Please try again.");
    } finally {
      setIsLoading(false);
    }
  }
  return <div style={{
    position: "relative",
    display: "inline-block",
    width: "100%"
  }}>
      {}
      {imageSrc && <img src={imageSrc} alt={imageAlt} style={{
    width: "100%",
    height: "auto",
    display: "block",
    borderRadius: "8px",
    opacity: 0.8,
    ...imageStyles
  }} />}

      {}
      <div style={imageSrc ? {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    zIndex: 10
  } : {
    display: "flex",
    justifyContent: "flex-start",
    margin: "1.25rem 0"
  }}>
        <button type="button" className="try-replo-btn" onClick={handleTryPrompt} disabled={isLoading} style={{
    backgroundColor: "#274AE2",
    color: "#ffffff",
    padding: "0.5rem 1.1rem",
    fontSize: "0.875rem",
    fontWeight: 600,
    fontFamily: "inherit",
    border: "none",
    borderRadius: "9999px",
    cursor: isLoading ? "not-allowed" : "pointer",
    lineHeight: 1.4,
    whiteSpace: "nowrap",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    WebkitFontSmoothing: "antialiased",
    boxSizing: "border-box",
    opacity: isLoading ? 0.7 : 1,
    boxShadow: "0 1px 2px rgba(15, 23, 42, 0.08)",
    transition: "background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease"
  }}>
          <span style={{
    visibility: isLoading ? "hidden" : "visible",
    display: "inline-flex",
    alignItems: "center",
    gap: "0.375rem"
  }}>
            {buttonCta}
            {ChevronIcon}
          </span>
          {isLoading && <span style={{
    position: "absolute",
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
              {LoaderIcon}
            </span>}
        </button>
      </div>

      {}
      <style>
        {`
          @keyframes spin {
            from {
              transform: rotate(0deg);
            }
            to {
              transform: rotate(360deg);
            }
          }
          .try-replo-btn:hover:not(:disabled) {
            background-color: #1f3ec0 !important;
            box-shadow: 0 4px 12px rgba(39, 74, 226, 0.35);
            transform: translateY(-1px);
          }
          .try-replo-btn:active:not(:disabled) {
            transform: translateY(0);
            box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
          }
          .try-replo-btn:focus-visible {
            outline: 2px solid #274AE2;
            outline-offset: 2px;
          }
        `}
      </style>

      {}
      {error && <div style={{
    marginTop: "12px",
    padding: "12px 16px",
    backgroundColor: "#fee",
    border: "1px solid #fcc",
    borderRadius: "6px",
    color: "#c33",
    fontSize: "14px",
    textAlign: "center"
  }} role="alert">
          {error}
        </div>}
    </div>;
};

When a page moves or you retire a URL, add a redirect so visitors and search engines land on the new address instead of a dead page.

Redirects live in the [Site Builder](/apps/website-builder): open **More options** (the sliders icon in the top bar), choose **Site settings**, and select the **Redirects** tab. You can also ask Replo in chat.

```text theme={null}
Add a permanent redirect from /old-sale to /summer-sale
```

<TryPromptButton prompt="Add a permanent redirect from /old-sale to /summer-sale" />

## Add a redirect

<Steps>
  <Step title="Open the Redirects tab">
    In the Site Builder, open **More options**, choose **Site settings**, and
    select **Redirects**.
  </Step>

  <Step title="Add a rule">
    Click **Add redirect**. If you already have rules, the button is **Add**.
  </Step>

  <Step title="Set From and To">
    **From** is the old path on this site. It must start with `/`, for example
    `/old-page`. **To** is another path on this site (`/new-page`) or a full
    address (`https://example.com/page`).
  </Step>

  <Step title="Choose Permanent or Temporary">
    **Permanent** tells search engines to update their links. **Temporary**
    keeps the old URL indexed. Use Permanent unless you plan to put the old
    URL back.
  </Step>

  <Step title="Save, then publish">
    Click **Done** on the rule, then **Save**. Redirects go live the next time
    you [publish](/publishing) the site.
  </Step>
</Steps>

If you leave with unsaved changes, Replo asks you to save or discard them.

## Path patterns

An exact path matches that page only. To cover a whole section, add `/:rest*`
so everything underneath moves too.

| From                | Matches                                                       |
| ------------------- | ------------------------------------------------------------- |
| `/old-page`         | Only `/old-page`                                              |
| `/old-blog/:rest*`  | `/old-blog` and everything under it, such as `/old-blog/post` |
| `/blog/:year/:slug` | Two required segments, for example `/blog/2026/launch`        |

Reuse the same name in **To** to keep the rest of the path: `/old-blog/:rest*`
to `/blog/:rest*` sends `/old-blog/post` to `/blog/post`. Leave the capture out
of **To** to send every match to one page.

Write `/old-blog/:rest*`, not `/old-blog/*`. A bare `*` does not capture
anything, and the form will reject it.

## Priority

Redirects run from top to bottom. The first match wins.

Drag a rule to change its priority. Put a specific exception above a catch-all.
If `/blogs/:rest*` sits above `/blogs/sale`, the sale rule never runs, and the
form flags it: "This redirect can't run because /blogs/:rest\* matches first."

## Permanent vs temporary

The form offers two types:

* **Permanent** (the default). Search engines replace the old URL with the new
  one. Use this when the move is lasting.
* **Temporary**. Search engines keep the old URL indexed. Use this for a
  short-term campaign or a page you will bring back.

## Custom redirects

Some redirects cannot be edited in this form, for example a rule that depends
on a cookie, a login state, or a destination computed in code. Those appear
under **Custom redirects** as read-only. Ask Replo in chat to change one.

## After you rename a page

Changing a page's URL in [Page settings](/features/site-page-settings) does not
create a redirect. Links to the old address stop working unless you add one
here. The Page settings URL field warns you about that when you change it.

## Query strings

A same-site destination keeps the visitor's query string when **To** does not
define one, so `/old-page?utm_source=ad` lands on `/new-page?utm_source=ad`. An
off-site destination drops the incoming query unless you include one in **To**.

## Languages

On a site with [languages](/features/languages) turned on, write **From** as
the logical path (`/old-page`). That rule applies in every language, and
same-site destinations pick up the visitor's language prefix automatically. A
language-prefixed source (`/en-CA/old-page`) matches that language only.

## FAQ

<AccordionGroup>
  <Accordion title="Do redirects go live as soon as I save?">
    No. Saving writes the rules to your site. They apply to visitors on the
    next [publish](/publishing).
  </Accordion>

  <Accordion title="Can I redirect to another website?">
    Yes. Put a full `https://` address in **To**.
  </Accordion>

  <Accordion title="Why can't I save a rule?">
    The form blocks a source that does not start with `/`, a destination that
    is not a path or a full address, a bare `*` instead of `/:rest*`, or a
    rule shadowed by one above it. Fix the highlighted field, or drag the
    more specific rule above the catch-all.
  </Accordion>

  <Accordion title="The tab shows Custom redirects. Can I edit those here?">
    No. Custom redirects are read-only on this tab. Ask Replo in chat to
    change one, rather than fighting the form.
  </Accordion>

  <Accordion title="What happens if I change a page's URL?">
    The page moves. Old links 404 unless you add a redirect from the previous
    path. Page settings reminds you of this when you edit the URL.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Site Builder" href="/apps/website-builder">
    Open Site settings and review your pages before you publish.
  </Card>

  <Card title="Publishing" href="/publishing">
    Publish so saved redirects go live.
  </Card>

  <Card title="Page and SEO settings" href="/features/site-page-settings">
    Change a page URL, then add a redirect from the old path.
  </Card>

  <Card title="Languages" href="/features/languages">
    How redirects apply across localized addresses.
  </Card>
</CardGroup>
