LW IT Solutions
« Blog Overview /Web Development/Tutorials / Tutorial: Checking a JSON Payload Before It...

Tutorial: Checking a JSON Payload Before It Goes Into a Tag

Tutorial: Checking a JSON Payload Before It Goes Into a Tag
Contents
  1. Why a JavaScript Object Is Not JSON
  2. The Five Errors That Raise an Exception
  3. The Two That Report Nothing
  4. Reading the Position a Parser Reports
  5. Checking It on the Command Line
  6. Where It Matters Most
  7. Sources

A payload that a parser rejects is annoying and harmless: something breaks immediately, in one place, and the fix takes a minute. A payload that a parser accepts and reads differently than intended is neither of those things.

Both kinds come from the same source. JSON looks like a JavaScript object and is a much narrower format, and the differences between them are exactly the list below.

A payload with seven numbered problems marked inline, and beneath it two columns separating the five that raise an exception from the two that change a value silently
Five of the seven stop the parser. The other two produce a document that parses cleanly and means something else.

Why a JavaScript Object Is Not JSON

Everything valid in JSON is valid JavaScript. The reverse does not hold, and the gap between them is where the errors live.

{                                     // JavaScript, not JSON
  'order_id': 9007199254740993,       // single quotes
  total: 129.90,                      // unquoted key
  items: [ { sku: "SKU-42", qty: 2, } ],   // trailing comma
  rabatt: NaN,                        // not a JSON value
  /* a comment */
}

JSON permits double quotes and nothing else, requires every key to be quoted, forbids a comma before a closing bracket, has no comments, and knows exactly seven value types: object, array, string, number, true, false and null. There is no undefined, no NaN, no Infinity and no date.

That last point is worth stating plainly, because it produces a recurring surprise: a date has no representation of its own. Whatever arrives is a string or a number that both sides have agreed to read as a date, and any disagreement about the format is invisible to the parser.

The Five Errors That Raise an Exception

These are the loud ones, and every one of them produces the same unhelpful message about an unexpected token.

Error What it looks like
Single quotes ‘order_id’ instead of “order_id”
Unquoted key total: 129.90 instead of “total”: 129.90
Trailing comma A comma before } or ]
Comment Anything after // or between /* and */
Raw line break in a string A newline inside quotes; it has to be \n

A sixth belongs in the same group without being visible at all: a byte order mark at the beginning of the file. It is three invisible bytes before the opening brace, and the parser reports an unexpected token at position 0 – which looks like the brace is the problem. A file that looks flawless and fails at position 0 has one, and an editor set to save without a BOM removes it.

The Two That Report Nothing

These are the ones worth hunting for on purpose, because nothing else will point at them.

The first is a duplicate key. The specification allows it, and the common behaviour is that the last one wins – so a document with "total" twice parses cleanly and carries the second value. Where the two are far apart in a long payload, the result is a number that is neither wrong-looking nor right.

{ "total": 129.90, "currency": "EUR", "total": 139.90 }

JSON.parse(...).total   →   139.90

The second is a large integer. Numbers in JavaScript are floating point, and integers stay exact only up to 2^53 − 1. An order number, an ID from a database, a Meta CAPI identifier – all of them regularly exceed that, and the parser rounds them without a word.

JSON.parse('{"id": 9007199254740993}').id   →   9007199254740992

JSON.parse('{"id": "9007199254740993"}').id →   "9007199254740993"

The rule that follows is short: an identifier is a string, always, even when it consists only of digits. Nothing is ever calculated with it, and a string survives every parser unchanged.

Reading the Position a Parser Reports

The position in the error message is a character offset into the whole document, which in a minified payload is a number without meaning.

The first step is therefore always to format the document, not to look for the error. A formatted payload puts the position onto a line, and the line above the reported one is usually where the fault actually is – a missing comma is noticed at the next token, not at the place it is missing from.

try {
  JSON.parse(text);
} catch (e) {
  const stelle = Number((e.message.match(/position (\d+)/) || [])[1]);
  if (!Number.isNaN(stelle)) {
    console.log(text.slice(Math.max(0, stelle - 60), stelle + 60));
    console.log(" ".repeat(Math.min(60, stelle)) + "^");
  }
}

Sixty characters either side of the position is enough to see the problem in almost every case, and the caret removes the counting. This is worth having as a snippet, because the alternative is opening a formatter, pasting, scrolling and losing the position.

Checking It on the Command Line

Where the payload comes out of a file or a request, a single command answers the question.

# valid? formatted output, or an error with a line number
jq . nutzlast.json

# only the answer, without the content
jq -e . nutzlast.json >/dev/null && echo "gueltig" || echo "ungueltig"

# find duplicate keys - jq keeps the last, this counts them
jq -r 'paths(scalars) | join(".")' nutzlast.json | sort | uniq -d

# large numbers that will lose precision
grep -oE '"[a-z_]+": *[0-9]{16,}' nutzlast.json

The third command is the one worth running on a payload that has never been checked. It lists the paths that occur more than once, which is the only mechanical way to find the silent case – and on a generated payload it finds something surprisingly often, because a template that appends a field in two branches produces exactly this.

Where It Matters Most

Three places turn a small JSON mistake into something that is hard to notice afterwards.

A JSON-LD block in the page is the first. A syntax error means search engines read no structured data at all, and the page keeps working perfectly – so nothing about the site suggests a problem, and the loss appears weeks later as missing rich results. A validator on the rendered page, not on the template, is the check that catches it.

A conversions API payload is the second. The receiving platform answers with an error, but that error is on a server-to-server response nobody is watching, and a failed event simply does not appear. This is the case where the duplicate key does the most damage: a payload with an event value twice sends the wrong one, and both the sender and the receiver consider the request successful.

A tag manager template configuration is the third. Its JSON is read once when the template is loaded, and a malformed field can leave the template installed but inert. What makes this one different is that it fails at the moment of import rather than at runtime – which is a better place to fail, and only if somebody reads the message.

What all three have in common: they are checked at the point where the payload is produced, not where it is consumed. A build step that runs the parser over every generated file costs nothing and catches all five loud errors before they leave the machine.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Write a comment

The email address is not published. Required fields are marked with an asterisk.

ALL ARTICLES & CATEGORIES

CCTV

Follow this category by RSS

Cloud & AI

Follow this category by RSS

Data Privacy

All 14 articles in this category Follow this category by RSS

Digital Analytics

All 51 articles in this category Follow this category by RSS

Digital Marketing

All 31 articles in this category Follow this category by RSS

IT & Networks

All 18 articles in this category Follow this category by RSS

Music Production

Follow this category by RSS

Raspberry PI

Follow this category by RSS

Smart Home

All 19 articles in this category Follow this category by RSS

Web Development

Follow this category by RSS

WordPress Plugins & Tricks

Follow this category by RSS