Runtime verified

Syntax

CloudPagesURL(pageId[, paramName1, paramValue1, paramNameN, paramValueN, ...])  →  string

Parameters

Name Type Required Description
pageId string | number Yes CloudPages page ID (number or string)
paramName1 string No Query parameter name
paramValue1 string No Query parameter value
paramNameN string No Additional query parameter name
paramValueN string No Additional query parameter value

Name and value are supplied as a pair, and the pairs repeat for as long as you need them. There is no upper bound on the argument count.

Example

%%[
  VAR @link
  SET @link = CloudPagesURL(39412)
]%%
<a href="%%=v(@link)=%%">Open the page</a>

Renders the landing page’s own published URL, unchanged and without a query string — the same address you would copy out of the page’s properties.

Add a pair when the target page needs a value, and read it back there with RequestParameter:

%%[
  VAR @link
  SET @link = CloudPagesURL(39412, "offer", "spring")
]%%
<a href="%%=v(@link)=%%">See your offer</a>

The rendered href now carries one extra query parameter holding a single encrypted token. Neither offer nor spring is readable in it — see below.

Return value

string — the published URL of the referenced page.

The value domain is open, so there is no set of sentinel values to test for. What is fixed is the shape: with no extra pairs it is the bare page URL; with pairs it is that same URL plus exactly one query parameter, whatever number of pairs you passed.

Behaviour

A plain call returns the page’s direct URL, not a wrapper. Called with a page ID from an ordinary anonymous page request, the result was byte-for-byte the referenced page’s own published address — same host, same path, no query string, and no tracking or redirect host in front of it. Nothing needs unwrapping before you can use it.

Extra arguments must come in pairs. One, three and five arguments all render. Two and four abort the request with HTTP 422 and discard everything already written, so a name left without its value takes the whole page down rather than being ignored.

A page ID that matches no page aborts the request. It does not return an empty string and it does not return an error value — the request fails outright with HTTP 422, discarding output already written. This is the single most important thing to know about the function: a mistyped ID looks exactly like a broken page, and gives you nothing to test for. Validate the ID before you build the link — see the card on this.

Pairs are encrypted, not appended. A pair produced one extra query parameter carrying a long opaque token in which neither the name nor the value could be found. A second pair only lengthened that same token. Do not expect to read your own parameters back out of the URL string.

Encoding a value is therefore moot. A value containing a space and an ampersand produced a result with no space and no ampersand anywhere in it. The characters that would need escaping never reach the URL as text in the first place.

The token changes on every request. The same call fetched twice returned two different tokens of equal length, so the result must never be compared, deduplicated or cached as an identity. Two calls inside a single render do match — a comparison that passes in one page is not evidence the value is stable.

The ID may be a number or a quoted string. Both spellings of the same ID produced the identical URL.

Show test script
%%[
  VAR @b, @pid, @known, @u1, @u2
  SET @b = RequestParameter("b")

  /* the page this script is deployed to, and that page's own URL */
  SET @pid = 39412
  SET @known = "your-subdomain.pub.sfmc-content.com/your-path"

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

  /* one argument: the returned string IS the page's own published URL,
     so the known URL is found at position 9, right after https:// */
  IF @b == "ar1" THEN
    OutputLine(Concat("--- ar1 start ---"))
    SET @u1 = CloudPagesURL(@pid)
    OutputLine(Concat("R=[", @u1, "]"))
    OutputLine(Concat("LEN=[", Length(Concat(@u1, "")), "]"))
    OutputLine(Concat("HOSTPOS=[", IndexOf(@u1, @known), "]"))
    OutputLine(Concat("QSPOS=[", IndexOf(@u1, "?"), "]"))
    OutputLine(Concat("--- ar1 done ---"))
  ENDIF

  /* one pair: a single query parameter appears, and neither the name nor
     the value can be found in the result */
  IF @b == "ar3" THEN
    OutputLine(Concat("--- ar3 start ---"))
    SET @u1 = CloudPagesURL(@pid, "k1", "v1")
    OutputLine(Concat("R=[", @u1, "]"))
    OutputLine(Concat("LEN=[", Length(Concat(@u1, "")), "]"))
    OutputLine(Concat("KPOS=[", IndexOf(@u1, "k1"), "]"))
    OutputLine(Concat("VPOS=[", IndexOf(@u1, "v1"), "]"))
    OutputLine(Concat("--- ar3 done ---"))
  ENDIF

  /* two pairs: still one query parameter, just a longer token */
  IF @b == "ar5" THEN
    OutputLine(Concat("--- ar5 start ---"))
    SET @u1 = CloudPagesURL(@pid, "k1", "v1", "k2", "v2")
    OutputLine(Concat("R=[", @u1, "]"))
    OutputLine(Concat("LEN=[", Length(Concat(@u1, "")), "]"))
    OutputLine(Concat("--- ar5 done ---"))
  ENDIF

  /* the ID as a quoted string behaves like the numeric literal */
  IF @b == "str" THEN
    OutputLine(Concat("--- str start ---"))
    SET @u1 = CloudPagesURL("39412")
    OutputLine(Concat("R=[", @u1, "]"))
    OutputLine(Concat("LEN=[", Length(Concat(@u1, "")), "]"))
    OutputLine(Concat("--- str done ---"))
  ENDIF

  /* a value holding a space and an ampersand: neither character appears
     in the result, because the pair never survives as text */
  IF @b == "enc" THEN
    OutputLine(Concat("--- enc start ---"))
    SET @u1 = CloudPagesURL(@pid, "q", "a b&c")
    OutputLine(Concat("R=[", @u1, "]"))
    OutputLine(Concat("SPACEPOS=[", IndexOf(@u1, " "), "]"))
    OutputLine(Concat("AMPPOS=[", IndexOf(@u1, "&"), "]"))
    OutputLine(Concat("--- enc done ---"))
  ENDIF

  /* two identical calls inside ONE render match; fetch this gate twice and
     compare the ar3 tokens across the two requests to see them differ */
  IF @b == "det" THEN
    OutputLine(Concat("--- det start ---"))
    SET @u1 = CloudPagesURL(@pid)
    SET @u2 = CloudPagesURL(@pid)
    OutputLine(Concat("SAME=[", IIf(@u1 == @u2, "identical", "different"), "]"))
    OutputLine(Concat("--- det done ---"))
  ENDIF

  /* argument counts the signature does not allow, and an ID matching no
     page: each aborts its own branch with HTTP 422 while every branch
     above still renders */
  IF @b == "ar0" THEN
    OutputLine(Concat("AR0_START=[x]"))
    OutputLine(Concat("R=[", CloudPagesURL(), "]"))
  ENDIF
  IF @b == "ar2" THEN
    OutputLine(Concat("AR2_START=[x]"))
    OutputLine(Concat("R=[", CloudPagesURL(@pid, "k1"), "]"))
  ENDIF
  IF @b == "ar4" THEN
    OutputLine(Concat("AR4_START=[x]"))
    OutputLine(Concat("R=[", CloudPagesURL(@pid, "k1", "v1", "k2"), "]"))
  ENDIF
  IF @b == "bad" THEN
    OutputLine(Concat("BAD_START=[x]"))
    OutputLine(Concat("R=[", CloudPagesURL(987654321), "]"))
  ENDIF
]%%

Two things this harness cannot reach. What the token resolves to on the target page needs a real send with a real subscriber, so the personalisation the official reference describes is untested here — only the token’s existence, its per-call variation and its absorption of the extra pairs were proven. And the reserved parameter names the official reference lists were not exercised at all, so that list stands unchallenged and unconfirmed.

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next No

See also