IsCHTMLBrowser
→ booleanReturns whether a user-agent string represents a CHTML browser (e.g. feature phones).
Runtime verified
Test scripts included
Syntax
Platform.Function.IsCHTMLBrowser(userAgentString)
1 argument
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
userAgentString |
string | Yes | User-agent value to evaluate |
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Parameters — Platform.Function.IsCHTMLBrowser(userAgentString)
*
* Proves:
* 1. The member exists and is invocable with exactly 1 argument (a
* successful call is the only reliable existence proof for a
* Platform.Function member).
* 2. return_type is boolean: typeof the result is "boolean", and the
* result is strictly true / strictly false — never null, never
* undefined, never a string.
* 3. userAgentString is REQUIRED: the 0-argument form throws.
* 4. max_args is 1: the 2-argument and 3-argument forms throw. There is no
* reachable optional second argument.
* 5. The predicate DISCRIMINATES: it answers true for user agents of CHTML
* feature-phone browsers and false for a modern desktop browser, so a
* PASS here is not a constant.
* 6. An empty string and a null argument both THROW rather than answering
* false — the parameter must carry an actual user-agent value.
* 7. Non-string primitives are coerced and answered false rather than
* throwing; an array argument throws.
* 8. It matches on user-agent SHAPE, not on the literal text "CHTML": the
* strings "chtml" and "CHTML" are both answered false.
* 9. There is no bare-name Core Library form — IsCHTMLBrowser(...) without
* the Platform.Function prefix throws "Object expected: IsCHTMLBrowser"
* even after Platform.Load.
*
* SCOPE: evidence gathered on a CloudPage GET only. The function is a pure
* predicate over its argument, so the CloudPage context does not restrict
* what can be proven — but the send-time path in which a real CHTML email
* client's user agent reaches this function is UNTESTED here.
*
* EXPECTED OUTPUT: every line starts with PASS. A FAIL means the runtime no
* longer matches the documented claim and the page must be revised.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var DESKTOP = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
var DOCOMO = "DoCoMo/2.0 SH902i(c100;TB;W24H12)";
var KDDI = "KDDI-SA31 UP.Browser/6.2.0.7.3.129 (GUI) MMP/2.0";
var SOFTBANK = "SoftBank/1.0/910T/TJ001/SN000000000000000 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1";
var UPBROWSER = "UP.Browser/6.2.3.8";
/* 1 + 2. The 1-argument call works and answers a genuine boolean. */
var chtml = Platform.Function.IsCHTMLBrowser(DOCOMO);
assert("typeof the result is boolean", String(typeof chtml), "boolean");
assert("the result is strictly true for a CHTML user agent", chtml === true ? "true" : "false", "true");
assert("the result is not null", chtml === null ? "true" : "false", "false");
assert("the result is not undefined", chtml === undefined ? "true" : "false", "false");
assert("the result is not the string 'true'", chtml === "true" ? "true" : "false", "false");
var desktop = Platform.Function.IsCHTMLBrowser(DESKTOP);
assert("typeof the negative result is boolean too", String(typeof desktop), "boolean");
assert("a modern desktop browser is strictly false", desktop === false ? "true" : "false", "true");
assert("the negative result is not undefined", desktop === undefined ? "true" : "false", "false");
/* 5. The predicate discriminates — several CHTML-era user agents answer true. */
assert("a DoCoMo/2.0 feature-phone user agent is true", Platform.Function.IsCHTMLBrowser(DOCOMO) ? "true" : "false", "true");
assert("a KDDI UP.Browser user agent is true", Platform.Function.IsCHTMLBrowser(KDDI) ? "true" : "false", "true");
assert("a SoftBank NetFront user agent is true", Platform.Function.IsCHTMLBrowser(SOFTBANK) ? "true" : "false", "true");
assert("a bare UP.Browser user agent is true", Platform.Function.IsCHTMLBrowser(UPBROWSER) ? "true" : "false", "true");
assert("a Chrome desktop user agent is false", Platform.Function.IsCHTMLBrowser(DESKTOP) ? "true" : "false", "false");
assert("an Outlook desktop user agent is false", Platform.Function.IsCHTMLBrowser("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; Microsoft Outlook 16.0.5)") ? "true" : "false", "false");
/* 8. It matches on user-agent shape, not on the literal word "CHTML". */
assert("the literal string 'chtml' is NOT treated as a CHTML browser", Platform.Function.IsCHTMLBrowser("chtml") ? "true" : "false", "false");
assert("the literal string 'CHTML' is NOT treated as a CHTML browser", Platform.Function.IsCHTMLBrowser("CHTML") ? "true" : "false", "false");
/* 3. userAgentString is required. */
assertThrows("arity 0 throws (userAgentString is required)", function () {
return Platform.Function.IsCHTMLBrowser();
});
/* 4. max_args is 1 — no optional second argument is reachable. */
assertThrows("arity 2 throws (max_args is 1)", function () {
return Platform.Function.IsCHTMLBrowser(DESKTOP, "x");
});
assertThrows("arity 3 throws (max_args is 1)", function () {
return Platform.Function.IsCHTMLBrowser(DESKTOP, "x", "y");
});
/* 6. An empty or null user agent throws instead of answering false. */
assertThrows("an empty-string user agent throws", function () {
return Platform.Function.IsCHTMLBrowser("");
});
assertThrows("a null user agent throws", function () {
return Platform.Function.IsCHTMLBrowser(null);
});
/* 7. Non-string primitives are coerced; an array throws. */
assert("a number argument is coerced and answered false", Platform.Function.IsCHTMLBrowser(123) ? "true" : "false", "false");
assert("a boolean argument is coerced and answered false", Platform.Function.IsCHTMLBrowser(true) ? "true" : "false", "false");
assertThrows("an array argument throws", function () {
return Platform.Function.IsCHTMLBrowser([]);
});
/* 9. No bare-name Core Library form exists. */
assertThrows("the bare-name form IsCHTMLBrowser(...) throws - Platform.Function is required", function () {
return IsCHTMLBrowser(DOCOMO);
});
</script>
Example
Platform.Response.Write(Platform.Request.UserAgent);
Platform.Response.Write("<br>Is CHTML: ");
Platform.Response.Write(
Platform.Function.IsCHTMLBrowser(Platform.Request.UserAgent)
);
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Example — write Platform.Request.UserAgent, then write
* Platform.Function.IsCHTMLBrowser(Platform.Request.UserAgent).
*
* Proves the shape of the documented example:
* 1. Platform.Request.UserAgent is readable inside a CloudPage request and
* stringifies without throwing.
* 2. The example's third line — feeding a user-agent value straight into
* IsCHTMLBrowser and writing the result — produces a genuine boolean
* that Write() renders as "true" / "false".
* 3. The example is meaningful because the answer follows the value fed
* in: the same three lines answer true for a CHTML feature-phone user
* agent and false for a desktop one.
* 4. The written output is the lowercase JavaScript boolean rendering, not
* "True"/"False" and not an empty string.
* 5. ENVIRONMENTAL NOTE, asserted rather than assumed: an HTTP client that
* sends no User-Agent header makes Platform.Request.UserAgent
* stringify to the empty string, and the example's call then throws —
* which is exactly the empty-string rule proven in the Parameters
* chapter, not a defect of the example. The assertion below records
* whichever of the two states this request is in, so the script is
* green from a real browser and from a header-less fetch alike.
*
* SCOPE: evidence gathered on a CloudPage GET only. Whether SFMC supplies a
* genuine CHTML client's user agent at email send time is UNTESTED here —
* no assertion depends on it.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
var DESKTOP = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
var DOCOMO = "DoCoMo/2.0 SH902i(c100;TB;W24H12)";
/* 1. Example line 1 — Platform.Request.UserAgent is readable. */
var ua = Platform.Request.UserAgent;
assert("Platform.Request.UserAgent is a CLR host value", String(typeof ua), "clr");
var uaText = "" + ua;
assert("Platform.Request.UserAgent stringifies without throwing", String(typeof uaText), "string");
/* 5. Record which of the two request states this is, and assert the
matching behaviour of the example's call. */
var hasUa = uaText.length > 0;
Platform.Response.Write("PASS request state -> [" + (hasUa ? "User-Agent header present: " + uaText : "no User-Agent header sent - the example's call must throw, per the empty-string rule") + "]\n");
var uaThrew = false;
var uaResultIsBoolean = false;
try {
uaResultIsBoolean = (typeof Platform.Function.IsCHTMLBrowser(Platform.Request.UserAgent)) === "boolean";
} catch (ex) {
uaThrew = true;
}
assert("the example's call throws exactly when no User-Agent header was sent", uaThrew ? "true" : "false", hasUa ? "false" : "true");
assert("when a User-Agent header IS present the example's call answers a boolean", (hasUa ? uaResultIsBoolean : true) ? "true" : "false", "true");
/* 2 + 3. The example's three lines, driven by an explicit user agent so the
assertion does not depend on what the requesting client sent. */
var chtmlAnswer = Platform.Function.IsCHTMLBrowser(DOCOMO);
assert("example line 3 answers a boolean for a CHTML user agent", String(typeof chtmlAnswer), "boolean");
assert("example line 3 answers true for a CHTML user agent", chtmlAnswer === true ? "true" : "false", "true");
var desktopAnswer = Platform.Function.IsCHTMLBrowser(DESKTOP);
assert("example line 3 answers a boolean for a desktop user agent", String(typeof desktopAnswer), "boolean");
assert("example line 3 answers false for a desktop user agent", desktopAnswer === false ? "true" : "false", "true");
assert("the answer follows the value fed in, so the example is not a constant", chtmlAnswer === desktopAnswer ? "true" : "false", "false");
/* 4. What Write() actually renders. */
var writtenTrue = "" + chtmlAnswer;
assert("Write() renders the positive answer as lowercase 'true'", writtenTrue, "true");
var writtenFalse = "" + desktopAnswer;
assert("Write() renders the negative answer as lowercase 'false'", writtenFalse, "false");
assert("the rendered answer is not the empty string", writtenTrue.length > 0 ? "true" : "false", "true");
Platform.Response.Write("PASS example output for a CHTML user agent -> [" + DOCOMO + "<br>Is CHTML: " + writtenTrue + "]\n");
Platform.Response.Write("PASS example output for a desktop user agent -> [Is CHTML: " + writtenFalse + "]\n");
</script>