Published just now • Last updated September 16, 2026 • ⏱️ 5 min read

Hackvertor tags can now ask a yes/no question about their input, and you can chain tags together with &&, || and ! so a conversion only runs when a condition holds. It works exactly like JavaScript's short-circuit operators, but inside Hackvertor's tag syntax.
Until now every tag in a Hackvertor expression always ran. If you wanted to base64 some input only when it was JSON, or fall back to a different decoder when the first one failed, you had to write a custom tag that did the branching itself. That is fine for one-offs, but it means every combination needs its own tag. I wanted the branching to live in the tag syntax instead, so that any tag could take part.
The answer is a new optional method on every tag class, check(), and a fifth tag operation to go with it. A tag that implements check() can be used as a condition, and a run of tags joined with && or || becomes an expression that decides which of them actually execute.
Hackvertor had four tag operations: encode, decode, autodecode and decodeEncode. The new one is check. It runs the tag's check() method and outputs true or false.
<@check(isJson)>{"a":1}</@check>
That outputs true, because the isJson tag, which is built in and installed by default, has a check() that validates the input as JSON. Feed it not json and you get false.
Only tags that implement check() offer the operation, so the check entry in the tag menu and the autocomplete only appear for those tags. On its own, a check tag is a handy way to test something about your input. It gets much more interesting once you combine it with other tags.
Two or more tags separated by && or || form an expression, as long as at least one of them is a check tag. The rules are the same as JavaScript:
A && B outputs B when A is truthy, otherwise A.A || B outputs A when A is truthy, otherwise B.!A negates A. Write the ! directly before the tag.&& binds tighter than ||, so A || B && C means A || (B && C).&& simply produces no output.Here is the simplest case. This base64-encodes the input only when it really is JSON, and otherwise outputs nothing:
<@check(isJson)>{"a":1}</@check> && <@encode(base64)>{"a":1}</@encode>
Negate the check to hex-encode everything that is not JSON:
!<@check(isJson)>plain text</@check> && <@encode(hex)>plain text</@encode>
The nice part is what counts as falsy. A tag that throws an error is falsy, so || doubles as a fallback. Here the base64 decode fails on invalid input, so the expression falls through to the hex encode:
<@check(isJson)>{}</@check> && <@decode(base64)>not base64!</@decode> || <@encode(hex)>fallback</@encode>
Expressions work inside other tags too, so the result of a condition can be encoded further:
<@encode(base64)><@check(isJson)>{}</@check> && <@encode(hex)>ok</@encode></@encode>
The full list of falsy values is false, an empty output, the text false, and a tag that threw an error. Anything else is truthy.
I was careful not to break existing input. Only whitespace may sit between a tag and the operator, and the operands must be tags. If a run of tags has no check tag in it, or any other text interrupts the run, the parser leaves everything exactly as it was. So && between two encode tags is still just text, and anything you had saved before this change produces the same output it always did.
A Hackvertor tag is a JavaScript class, and check() is just one more optional method on it. It receives the input plus the same arguments as encode(), and returns true or false. It can be async if it needs to be.
class MyTag { encode(input) { return encodeURIComponent(input); } decode(input) { return decodeURIComponent(input); } matches(input) { // Always anchor with ^ and end with $. return /^(?:%[a-f0-9]{2})+$/i.exec(input); } check(input, arg1) { // Optional. A yes/no question about the input. Returns true or false. return this.matches(input) !== null; } }
If you already have a matches() method for the autodecoder, a check is often a one-liner that reuses it, as above. But a check doesn't have to be about encoding at all. Anything you can answer with a boolean works: is this valid JSON, does this look like a JWT, is this IP in a private range, does this string contain a null byte.
Adding the method is all you need to do. As soon as a tag has a check(), the check operation appears in the menu for that tag, the tag editor's autocomplete offers it, and the test input in the tag editor gains a <@check(MyTag)>test</@check> line alongside the encode and decode ones. Tags can also call each other's checks from inside their own code with hv.tags.tagName.check(input).
Because tags live in the Tag Store, a check you write once is available to anyone who installs your tag, and they can immediately combine it with every other tag they have.
The feature is live now on hackvertor.co.uk. The help page has the full reference for conditions, and the tag editor's sample code includes a check() you can adapt. Add a check() to one of your tags, publish it to the Tag Store, and see what conditions other people build with it.