Char
Returns the character for a numeric character code. Notes that the code domain is not capped at 255.
Syntax
Char(characterCode[, numRepetitions]) → string
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
characterCode |
string | number | Yes | Character code, as a whole number |
numRepetitions |
string | number | No | Number of times to repeat the returned character, as a whole number |
Example
%%[
VAR @letter
SET @letter = Char(65)
]%%
Letter: %%=v(@letter)=%%
Renders Letter: A.
The usual reason to reach for it is a character you cannot type into the source safely — a quote inside a quoted string, or a line break:
%%[
VAR @quoted
SET @quoted = Concat(Char(34), AttributeValue("ProductName"), Char(34))
]%%
Return value
string — the character for the supplied code, repeated when a repetition count is given.
The value domain is open: any code that resolves produces its character, and a repetition count of 0 produces the empty string. There is no closed set of sentinel values to test for.
Behaviour
The optional second argument repeats the character. Char(65,3) gives AAA and Char(65,1) gives A. A count of 0 produces an empty string — Length(Char(65,0)) is 0.
Numeric strings are accepted for both parameters. Char("65") gives the same A as the numeric literal, and Char(65,"3") gives the same AAA.
Extended-ASCII codes resolve to their Latin-1 character. Char(190) and Char(255) each render a single character, at codepoint 190 and 255 respectively rather than as a multi-byte sequence.
Control codes are produced verbatim. Char(0), Char(9), Char(10), Char(13) and Char(32) each return one character — including the NUL byte, which renders as codepoint 0 in the response and measures Length 1. They are invisible in rendered output, so measure them rather than looking at them.
A decimal code, a decimal repeat count, a negative repeat count, a boolean, and a non-numeric string all abort the page. Char(65.7), Char(65,2.5), Char(65,-1), Char(true) and Char("abc") each aborted the page with HTTP 422, so nothing on the page survives. There is no error value to test for — guard the arguments before the call.
The code domain is not capped at 255
This is the load-bearing finding, and the official reference frames the domain as extended ASCII without saying what a larger number does.
| Call | Renders |
|---|---|
Char(256) |
the character at codepoint 256 |
Char(9731) |
the character at codepoint 9731 |
Char(-1) |
the character at codepoint 65535 |
Char(65601) |
A — codepoint 65 |
Char(128512) |
the character at codepoint 62976 |
Codes are treated as 16-bit code-unit values, not as bytes and not as full Unicode codepoints. Anything at or above 65536 wraps: 65601 is 65601 - 65536 = 65, which is why it renders A, and a code in the astral range collapses to a single unrelated code unit instead of the emoji a caller might expect. Every one of these returned Length 1, so the function never produces a surrogate pair.
Each literal above occupies a single codepoint in the response, which is what distinguishes the intended character from a mis-decoded multi-byte sequence.
The capability is catalogued on Differs from official docs. The docs are silent here rather than wrong, so the entry is not flagged as contradicting them — but a code outside 0–255 has no documented contract, so do not lean on it for portability.
Show test script
%%[
VAR @b
SET @b = RequestParameter("b")
/* documented forms: printable codes, extended ASCII, the repeat count */
IF @b == "safe" THEN
OutputLine(Concat("C65=[", Char(65), "]"))
OutputLine(Concat("C97=[", Char(97), "]"))
OutputLine(Concat("C48=[", Char(48), "]"))
OutputLine(Concat("C34=[", Char(34), "]"))
OutputLine(Concat("C39=[", Char(39), "]"))
OutputLine(Concat("C190=[", Char(190), "]"))
OutputLine(Concat("C255=[", Char(255), "]"))
OutputLine(Concat("LEN65=[", Length(Char(65)), "]"))
OutputLine(Concat("LEN190=[", Length(Char(190)), "]"))
OutputLine(Concat("LEN255=[", Length(Char(255)), "]"))
OutputLine(Concat("R3=[", Char(65,3), "]"))
OutputLine(Concat("R1=[", Char(65,1), "]"))
OutputLine(Concat("LENR3=[", Length(Char(65,3)), "]"))
ENDIF
/* control and whitespace codes - read these as raw bytes, not on a console */
IF @b == "cp" THEN
OutputLine(Concat("P10=[", Char(10), "]"))
OutputLine(Concat("P13=[", Char(13), "]"))
OutputLine(Concat("P32=[", Char(32), "]"))
OutputLine(Concat("P0=[", Char(0), "]"))
OutputLine(Concat("P9=[", Char(9), "]"))
OutputLine(Concat("LENC0=[", Length(Char(0)), "]"))
ENDIF
/* numeric strings are accepted for either parameter */
IF @b == "sc" THEN
OutputLine(Concat("SC=[", Char("65"), "]"))
ENDIF
IF @b == "sr" THEN
OutputLine(Concat("SR=[", Char(65,"3"), "]"))
ENDIF
/* a zero repeat count yields an empty string */
IF @b == "r0" THEN
OutputLine(Concat("R0=[", Char(65,0), "]"))
OutputLine(Concat("LENR0=[", Length(Char(65,0)), "]"))
ENDIF
/* codes past the documented 0-255 range still resolve */
IF @b == "c256" THEN
OutputLine(Concat("C256=[", Char(256), "]"))
OutputLine(Concat("LENC256=[", Length(Char(256)), "]"))
ENDIF
IF @b == "cbig" THEN
OutputLine(Concat("CBIG=[", Char(9731), "]"))
OutputLine(Concat("LENCBIG=[", Length(Char(9731)), "]"))
ENDIF
/* out-of-range codes wrap into the 16-bit code-unit range */
IF @b == "cn" THEN
OutputLine(Concat("CN=[", Char(-1), "]"))
ENDIF
IF @b == "cwrap" THEN
OutputLine(Concat("W65601=[", Char(65601), "]"))
OutputLine(Concat("LENW=[", Length(Char(65601)), "]"))
ENDIF
IF @b == "castral" THEN
OutputLine(Concat("AST=[", Char(128512), "]"))
OutputLine(Concat("LENAST=[", Length(Char(128512)), "]"))
ENDIF
/* every branch below aborts the page: the start marker never renders */
IF @b == "rn" THEN
OutputLine(Concat("--- rn start ---"))
OutputLine(Concat("RN=[", Char(65,-1), "]"))
ENDIF
IF @b == "cdec" THEN
OutputLine(Concat("--- cdec start ---"))
OutputLine(Concat("CDEC=[", Char(65.7), "]"))
ENDIF
IF @b == "rdec" THEN
OutputLine(Concat("--- rdec start ---"))
OutputLine(Concat("RDEC=[", Char(65,2.5), "]"))
ENDIF
IF @b == "cb" THEN
OutputLine(Concat("--- cb start ---"))
OutputLine(Concat("CB=[", Char(true), "]"))
ENDIF
IF @b == "cbad" THEN
OutputLine(Concat("--- cbad start ---"))
OutputLine(Concat("CBAD=[", Char("abc"), "]"))
ENDIF
IF @b == "a0" THEN
OutputLine(Concat("--- a0 start ---"))
OutputLine(Concat("A0=[", Char(), "]"))
ENDIF
IF @b == "a3" THEN
OutputLine(Concat("--- a3 start ---"))
OutputLine(Concat("A3=[", Char(65,2,3), "]"))
ENDIF
]%%
OutputLine given a bare string literal renders an empty line. Wrap the argument in Concat() or your start and done markers vanish silently — which looks exactly like the function failing.
A console that is not reading the response as UTF-8 turns a non-ASCII character into mojibake and can make a correct result look wrong. Dump the rendered value as codepoints before drawing any conclusion.
Availability
| Platform | Available |
|---|---|
| Marketing Cloud Engagement | Yes |
| Marketing Cloud Next | No |
See also
- Differs from official docs — the uncapped code domain in full
Concat— joins the characters you build withCharLength— how the resulting characters are counted- Official reference
- ampscript.guide