Changes from previous post on Reddit: Corrected speed comparison of rendering methods, and added info on critical iOS 17 bug.
The trick works because Shortcuts runs embedded JS when it tries to render an HTML page. Callbacks or async functions are not supported (unless they finish within < 0.2 sec). For networking,
XMLHttpRequest works on non-iOS 15.
Provide your JS code inside the
<script> tags along with the
data:text/html;charset=utf-8, prefix in a URL action:
No other tags are required such as
<meta>, and the code part doesn’t have to be encoded in base64 (except for some cases on iOS 17; refer below). The charset part is necessary to handle Unicode characters.
Inserting variables directly into JS code is possible, but only if you know it’s safe to do so:
This can fail if the text contains characters such as
\ or strings like
</script>, or if the number is Eastern Arabic like
١٢٣ or contains the decimal comma like
0,023. Therefore, it is best to pass input variables in a dictionary using the “Set Dictionary Value” or “Dictionary” action:
Output should be written onto the web page using
document.body.textContent = output. To prevent output alterations (e.g. changing
<, a new line or multiple spaces into a single space, losing
<tag-like> strings), it is safer to URL-encode it using
encodeURIComponent(). And again, to pass values correctly in various regions, it is better to produce the output as a JSON object and stringify it using
<script>document.write(output)</script> can be used instead of
<body/><script>document.body.textContent = output</script> but it uses more memory space.
Since Shortcuts treats web pages as Rich Text, the final output from a rendered page can be converted to text easily. After that, the URL-encoded output has to be decoded back. There are four known ways to produce rich text output (then URL-decode it) from a data URI:
- Get Contents of Web Page
- Get File of Type
- Get File of Type
- URL as Rich Text
They generate the same result at about the same speed, but the last one consumes less memory because it has one less action. The speed comparisons in the previous post were totally wrong; they are equally fast.
iOS 17 has introduced a new bug.
A data URI will output blank Rich Text if it contains the
# symbol (the number sign, pound sign, hash, hashtag, crosshatch, octothorpe, or whatever).
This affects any JS code that can contain the symbol. There are two ways to conceal them from the URI:
- In JS code, fortunately,
#characters most likely appear within string literals; in this case, they can be replaced with
- If they appear elsewhere such as in html or css, the entire data needs to be base64-encoded. This is much slower than Replace Text. Please note that a base64 data URI split into every 76 characters runs faster than the same base64 URI in a single line.
Finally, here’s a sample shortcut that combines all of the above: