Runtime verified

Syntax

RedirectTo(url)  →  string
1 argument — exactly

Parameters

Name Type Required Description
url string | number Yes Target URL

Example

%%[
  VAR @target
  SET @target = "https://example.com/offer?a=1&b=2"
]%%
<a href="%%=RedirectTo(@target)=%%">See the offer</a>

Inside a tracked send this makes the click countable. On a CloudPage the href is simply the address you passed, ampersand and all — the response is still HTTP 200 and carries no Location header, so nothing about the page changes.

When a link URL is assembled from variables, wrap the final address in RedirectTo so the click still counts. The temptation is to build the whole <a> tag by hand with Concat and print it with v() — but a link emitted that way is invisible to link tracking.

<!-- good: RedirectTo preserves click tracking -->
%%[
  SET @myParam = "bar"
  SET @url = Concat("https://mydomain.com/somePath?foo=", @myParam)
]%%
<a href="%%=RedirectTo(@url)=%%">demo link</a>
<!-- bad: hand-built anchor via Concat + v() is not tracked -->
%%[
  SET @myParam = "bar"
  SET @url = Concat('<a href="', "https://mydomain.com/somePath?foo=", @myParam, '">demo link</a>')
]%%
%%=v(@url)=%%

Both render a working link, but only the first is counted as a click. When the URL carries parameters, URL-encode the values before building it (see URLEncode) — an unencoded value can break the resulting link.

Return value

string — the link-tracking target for the supplied address during a tracked send; on a CloudPage the supplied value unchanged.

The value domain is open, so there is no set of sentinel values to test for. An empty argument answers an empty string at length zero rather than aborting.

Behaviour

The name is misleading: no redirect is emitted. Every call was fetched with automatic redirect following switched off so the status line could be read literally. The response was HTTP 200 every time, with no Location header at all.

It does not halt the script. Output written before the call is delivered, output written after it is delivered, and the enclosing block runs to its end. Treating this function as a way to send a visitor elsewhere from a landing page does not work — that is not what it does.

On a page the argument comes straight back. A URL carrying two query parameters returned at its original length with the ampersand intact and no tracking wrapper around it. Calling it inline inside a concatenation behaves exactly like assigning it first.

Nothing is validated. A word that is not a URL comes back unchanged, an empty string comes back empty, and a bare number comes back as its decimal digits.

Show test script
%%[
  VAR @b, @rt
  SET @b = RequestParameter("b")

  /* known-good control: renders on every request, so a run of HTTP 422s
     can be told apart from a broken deploy */
  OutputLine(Concat("CTRL=[", Uppercase("ok"), "]"))
  OutputLine(Concat("GATE=[", @b, "]"))

  /* the markers before and after the call are the point: both are
     delivered, and the response is HTTP 200 with no Location header */
  IF @b == "rt" THEN
    OutputLine(Concat("--- rt start ---"))
    OutputLine(Concat("RT_BEFORE=[written-before]"))
    SET @rt = RedirectTo("https://example.com/target?a=1&b=2")
    OutputLine(Concat("RT_RET=[", @rt, "] LEN=[", Length(@rt), "]"))
    OutputLine(Concat("RT_AFTER=[written-after]"))
    OutputLine(Concat("--- rt done ---"))
  ENDIF

  /* the inline form, to rule out the assignment being what suppresses
     the redirect */
  IF @b == "rtinline" THEN
    OutputLine(Concat("--- rtinline start ---"))
    OutputLine(Concat("RTI_BEFORE=[written-before]"))
    OutputLine(Concat("RTI=[", RedirectTo("https://example.com/inline"), "]"))
    OutputLine(Concat("RTI_AFTER=[written-after]"))
    OutputLine(Concat("--- rtinline done ---"))
  ENDIF

  /* values that are not usable URLs: none of them is rejected */
  IF @b == "rtempty" THEN
    OutputLine(Concat("--- rtempty start ---"))
    SET @rt = RedirectTo("")
    OutputLine(Concat("RT_EMPTY=[", @rt, "] LEN=[", Length(@rt), "]"))
    OutputLine(Concat("--- rtempty done ---"))
  ENDIF

  IF @b == "rtnonurl" THEN
    OutputLine(Concat("--- rtnonurl start ---"))
    SET @rt = RedirectTo("nothing-like-a-url")
    OutputLine(Concat("RT_NONURL=[", @rt, "] LEN=[", Length(@rt), "]"))
    OutputLine(Concat("--- rtnonurl done ---"))
  ENDIF

  IF @b == "rtnum" THEN
    OutputLine(Concat("--- rtnum start ---"))
    SET @rt = RedirectTo(42)
    OutputLine(Concat("RT_NUM=[", @rt, "] LEN=[", Length(@rt), "]"))
    OutputLine(Concat("--- rtnum done ---"))
  ENDIF

  /* argument counts the signature does not allow: each aborts its own
     branch with HTTP 422 while every branch above still renders */
  IF @b == "rt0" THEN
    OutputLine(Concat("RT0_START=[x]"))
    OutputLine(Concat("RT0=[", RedirectTo(), "]"))
  ENDIF
  IF @b == "rt2" THEN
    OutputLine(Concat("RT2_START=[x]"))
    OutputLine(Concat("RT2=[", RedirectTo("https://example.com/a", "https://example.com/b"), "]"))
  ENDIF
]%%

What a page cannot show is the function’s actual purpose — producing the tracked target inside a send, where clicks are attributed to a subscriber. That needs a real send. The official reference never claims a redirect happens at render time, so the pass-through is a limit of what a page can show rather than a contradiction.

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next No

See also