JSON trips up a lot of people who are new to Tines Stories, and it's rarely a sign you're doing something wrong. Tines Stories is low-code, but it's still a development environment, and the apps and APIs you connect to expect well-formed data to work at all. The good news is that almost every JSON problem in Tines Stories comes down to a single idea. Once that idea clicks, you'll know when to convert data to a JSON string, when to leave it alone, and when hand-escaping is helping you versus quietly breaking things.
This article explains that core idea, surveys the common places where stringifying is (and isn't) needed, lists the functions that do the work, and clears up the escaping questions that cause the most self-inflicted errors.
The one idea everything depends on: object or text
In a story, every value is either a structured object (an array or a JSON object) or a piece of text. A lot of "my JSON is broken" problems are really just a value being text when you needed an object, or an object when you needed text.
Which one you get is decided by the mode of the field you're writing in:
Formula mode. The field starts with
=, and the value keeps its native type. So=get_user.bodystays a real object, and an array stays an array.Text mode. You reference data with a
<<pill>>inside text, and the referenced value is converted to text and joined with whatever surrounds it.
That single distinction is the lever you'll reach for again and again. If an action downstream is complaining that it received a string when it wanted an object (or the reverse), the mode of the field is the first thing to check.
The functions that do the work
Tines Stories gives you a small set of functions for moving between objects and JSON text. You can use them in formula mode, and they behave as follows:
`JSON` or `TO_JSON`. Converts an object into a compact JSON string. The two names are interchangeable. This is "stringifying."
`NEAT_JSON`. Does the same conversion, but pretty-printed with indentation. Reach for this when a human will read the result, such as a log line or a case note.
`JSON_PARSE`. Converts a JSON string back into a real object. If the text isn't valid JSON, it logs a message and returns the original input unchanged rather than raising an error, so a malformed string can pass through silently.
`IS_JSON`. Returns true or false for whether a piece of text is valid JSON. It expects a string, so check the type first if you're not certain you have one.
Do you need to stringify? A quick guide
Stringifying means turning an object into JSON text with TO_JSON (or NEAT_JSON). You need it only when the destination genuinely wants text that happens to contain JSON.
Reach for TO_JSON in cases like these:
Storing or showing JSON as text. A log message, an event note, a plaintext resource, or a default value on a page or form.
Nested JSON. An API that wants a JSON string tucked inside one field of a larger JSON body, often a field named something like "metadata" or "payload."
Readable output for people. Use
NEAT_JSONso the indentation makes it easy to scan.
Just as often, Tines Stories is already serializing for you, and adding TO_JSON yourself causes the exact problem you're trying to avoid. Leave the object as an object in these cases:
The body of an HTTP request action. Put the object in a formula-mode field and let the action serialize the whole payload. If you stringify it first, the action receives text and encodes it a second time, which produces a double-encoded result with escaped quotes throughout.
Passing data between actions. Keep the value in formula mode so an array stays an array and an object stays an object all the way through.
Before Base64 encoding.
BASE64_ENCODEalready converts objects, arrays, booleans, and numbers to JSON for you, so there's no need to stringify first.
Going the other way: parsing text into an object
Sometimes an upstream system hands you JSON as text, for example a webhook field or an API response that returns a JSON string inside another string. To navigate into it, convert it back into an object with JSON_PARSE:
=JSON_PARSE(get_ticket.body.metadata)
Because JSON_PARSE returns the input unchanged when the text isn't valid JSON, it's worth checking first when the data might be unreliable:
=IF(IS_JSON(get_ticket.body.metadata), JSON_PARSE(get_ticket.body.metadata), {})Escaping: necessary, superfluous, or harmful
Escaping is where newcomers lose the most time, so here's the honest version: manual escaping is almost never the right tool in Tines Stories. Both TO_JSON and formula mode handle escaping for you, and they do it correctly, including quotes, newlines, and Unicode characters.
It helps to sort escaping into three buckets:
Harmful. Hand-adding backslashes around quotes in a formula, wrapping a formula value in quotes, or running an object through
TO_JSONand then escaping the result again. Each of these double-escapes your data, which is the single most common way people break their own JSON.Superfluous. Escaping data that's already flowing through formula mode or through
TO_JSON. The work is already done.The kind that actually matters. When you build a JSON string by hand in text mode and drop a
<<pill>>into it, a quote or newline inside that data will break the surrounding JSON.
For that last case, the fix is not to escape by hand. It's to stop hand-building the string. Build the payload in formula mode with an object literal so Tines Stories does the escaping:
={name: get_user.body.name, tags: get_user.body.tags}
Or, if you only need to drop one risky value into a larger structure, wrap just that value in TO_JSON so it becomes a properly escaped JSON fragment.
A quick mental checklist
When JSON isn't behaving, run through these in order:
Check the mode. Is the field in text mode when it should be formula mode, or the reverse?
Confirm the type. Use
TYPE()to see whether you actually have an object or a string.Stringify only at the edge. Convert to text with
TO_JSONonly when the destination wants JSON text, not when an action will serialize for you.Parse when you receive text. Use
JSON_PARSE, guarded byIS_JSONif the data might be malformed.Resist manual escaping. Let formula mode and
TO_JSONhandle quotes and newlines for you.
None of this means JSON in Tines Stories is harder than it should be. It means the same care any developer gives to data structure applies here too. Get the object-versus-text question right, and the rest tends to fall into place.
