<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Aniket Patil]]></title><description><![CDATA[Aniket Patil]]></description><link>https://aniketpatil-peepals.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 02 Nov 2026 10:55:21 GMT</lastBuildDate><atom:link href="https://aniketpatil-peepals.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Adding NewsArticle Structured Data to a News Site with JSON-LD (Without Breaking Your Pages)]]></title><description><![CDATA[If you run a news site or a blog, search engines can understand your pages better when you describe them with structured data. The common way to do that is…]]></description><link>https://aniketpatil-peepals.hashnode.dev/adding-newsarticle-structured-data-to-a-news-site-with-json-ld-without-breaking-your-pages</link><guid isPermaLink="true">https://aniketpatil-peepals.hashnode.dev/adding-newsarticle-structured-data-to-a-news-site-with-json-ld-without-breaking-your-pages</guid><category><![CDATA[SEO]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[structured data]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[news]]></category><dc:creator><![CDATA[Aniket Patil]]></dc:creator><pubDate>Wed, 21 Oct 2026 10:11:08 GMT</pubDate><content:encoded><![CDATA[<p>If you run a news site or a blog, search engines can understand your pages better when you describe them with structured data. The common way to do that is a small block of JSON-LD in the page that says, in a machine-readable way, "this is a news article, here is its headline, author, publish date and image."</p>
<p>This post shows how to generate that block from your article data, avoid two common bugs, and test the result.</p>
<h3>What JSON-LD is</h3>
<p>JSON-LD (JavaScript Object Notation for Linked Data) is a way to embed structured data in a page using a <code>&lt;script type="application/ld+json"&gt;</code> tag. The vocabulary comes from <a href="https://schema.org/">schema.org</a>, which defines types such as <code>Article</code>, <code>NewsArticle</code> and <code>BlogPosting</code> and the properties each one can have.</p>
<p>Google's <a href="https://developers.google.com/search/docs/appearance/structured-data/article">Article structured data documentation</a> covers all three types. It lists <strong>no required properties</strong> for articles, but recommends several: <code>headline</code>, <code>image</code>, <code>datePublished</code>, <code>dateModified</code> and <code>author</code>. Adding them helps search engines show the right title, image, date and byline.</p>
<h3>A minimal NewsArticle block</h3>
<p>Here is what we want to generate:</p>
<pre><code class="language-json">{
  "@context": "https://schema.org",
  "@type": "NewsArticle",
  "headline": "City council approves new cycle lanes",
  "image": [
    "https://example.com/images/cycle-lanes-16x9.jpg"
  ],
  "datePublished": "2026-10-19T08:30:00+05:30",
  "dateModified": "2026-10-19T11:05:00+05:30",
  "author": [
    {
      "@type": "Person",
      "name": "Asha Rao",
      "url": "https://example.com/authors/asha-rao"
    }
  ]
}
</code></pre>
<p>Note the dates: use ISO 8601 with a time zone offset. A date with no time zone forces search engines to guess.</p>
<h3>Generating it from your article data</h3>
<p>Hand-writing JSON-LD for every story doesn't scale. Generate it from whatever your CMS already stores. Here's a small framework-agnostic JavaScript function:</p>
<pre><code class="language-javascript">function buildNewsArticleJsonLd(article) {
  const data = {
    "@context": "https://schema.org",
    "@type": "NewsArticle",
    headline: article.title,
    datePublished: new Date(article.publishedAt).toISOString(),
    dateModified: new Date(article.updatedAt ?? article.publishedAt).toISOString(),
    author: article.authors.map((a) =&gt; ({
      "@type": "Person",
      name: a.name,
      ...(a.profileUrl &amp;&amp; { url: a.profileUrl }),
    })),
  };

  if (article.images?.length) {
    data.image = article.images.map((img) =&gt; img.url);
  }

  return data;
}
</code></pre>
<p>A few details:</p>
<ul>
<li><strong><code>dateModified</code> falls back to <code>datePublished</code></strong> when a story has never been updated, so the field is always present and never earlier than the publish date.</li>
<li><strong>Authors are an array of <code>Person</code> objects</strong> with a profile URL where you have one. That handles single and multiple bylines the same way. If a piece genuinely has no individual author, <code>Organization</code> is also a valid <code>@type</code>.</li>
<li><strong><code>toISOString()</code></strong> returns UTC with a <code>Z</code> suffix. That's valid ISO 8601, so you don't need to format local offsets yourself.</li>
</ul>
<h3>Bug #1: Breaking out of the script tag</h3>
<p>The obvious way to put this in a page is:</p>
<pre><code class="language-javascript">const html = `&lt;script type="application/ld+json"&gt;${JSON.stringify(data)}&lt;/script&gt;`;
</code></pre>
<p>This has a subtle problem. <code>JSON.stringify</code> does not escape <code>&lt;</code>. If a headline or author name ever contains the text <code>&lt;/script&gt;</code>, whether by accident or because someone typed it on purpose, the browser closes your script tag early and treats the rest as HTML. On a site that accepts any user-supplied text, that's an injection risk.</p>
<p>The fix is to escape <code>&lt;</code> after serialising:</p>
<pre><code class="language-javascript">function toJsonLdScript(data) {
  const json = JSON.stringify(data).replace(/&lt;/g, "\\u003c");
  return `&lt;script type="application/ld+json"&gt;${json}&lt;/script&gt;`;
}
</code></pre>
<p><code>&lt;</code> is still a valid way to write <code>&lt;</code> inside a JSON string, so search engines read the same data, but the browser no longer sees a closing tag.</p>
<p>If you use a framework that injects raw HTML, such as <code>dangerouslySetInnerHTML</code> in React, the same escaping applies. The framework won't do it for you.</p>
<h3>Bug #2: Structured data that doesn't match the page</h3>
<p>Structured data should describe what readers actually see. Common mismatches:</p>
<ul>
<li>The JSON-LD headline is an SEO title that doesn't match the visible headline.</li>
<li><code>dateModified</code> updates on every deploy or cache rebuild, even when the story itself hasn't changed.</li>
<li>The image in JSON-LD isn't on the page at all.</li>
</ul>
<p>The second one is easy to cause by accident. Take <code>dateModified</code> from the time an editor last changed the story's content, not from the file's last-write time or the build time.</p>
<h3>Testing</h3>
<p>Use two free tools:</p>
<ol>
<li><strong><a href="https://search.google.com/test/rich-results">Google's Rich Results Test</a></strong> checks whether Google can read your markup and whether the page is eligible for rich results.</li>
<li><strong><a href="https://validator.schema.org/">Schema Markup Validator</a></strong> checks your markup against the full schema.org vocabulary, independent of any search engine.</li>
</ol>
<p>Run both on a few real article URLs after deploying, including one with multiple authors and one that has been updated after publishing.</p>
<h3>Putting it together</h3>
<pre><code class="language-javascript">const article = {
  title: "City council approves new cycle lanes",
  publishedAt: "2026-10-19T03:00:00Z",
  updatedAt: "2026-10-19T05:35:00Z",
  authors: [{ name: "Asha Rao", profileUrl: "https://example.com/authors/asha-rao" }],
  images: [{ url: "https://example.com/images/cycle-lanes-16x9.jpg" }],
};

const scriptTag = toJsonLdScript(buildNewsArticleJsonLd(article));
// insert scriptTag into the &lt;head&gt; or &lt;body&gt; of the article page
</code></pre>
<h3>Wrapping up</h3>
<p>Structured data is a small amount of code with a lot of quiet benefits: clearer search results and a cleaner signal of who wrote what and when. Generate it from your real article data, escape it before inserting it into HTML, keep it in sync with what readers see, and test it on real pages.</p>
<p><em>The author writes for the Technology section of Peepals, a seven-section news network. <a href="https://peepalsglobal.com/">https://peepalsglobal.com/</a></em></p>
]]></content:encoded></item></channel></rss>