jQuery / Read meta Tag Values

Read a meta value by selecting the tag and calling .attr("content"). For a description, use $('head meta[name="description"]').attr("content"). Select Open Graph og:title by property rather than name.

Match the identifying and value attributes

The meta element supplies metadata, information about the document. In name="description", name identifies the kind and content holds the value. A meta element is not a paragraph with inner text; use .attr("content") rather than .text() or the form-value method .val().

Open Graph uses property="og:title". name="og:title" matches a different attribute and will not find it. A charset declaration stores its value in charset itself. Inspect actual markup rather than assuming every meta has content.

Single quotes around the JavaScript string and double quotes around attribute values keep fixed selectors readable. There is no need to construct an arbitrary selector from external input for this task.

Complete browser example

Save everything as UTF-8 meta-demo.html and open it in a browser. Internet loads the official jQuery file 4.0.0. No server or installation is needed. Reading, duplication, updated DOM values and reset were executed in Windows Edge with 3.7.1 and 4.0.0.

demo-empty and demo-no-content deliberately expose blank and missing attributes. Do not treat a name meta without content as valid production authoring. The single og:title is also not a complete Open Graph configuration.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Original page summary">
  <meta property="og:title" content="Meta demo">
  <meta name="demo-empty" content="">
  <meta name="demo-no-content">
  <title>Read meta attributes</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
    button { font: inherit; margin: 4px; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Read the current document's metadata</h1>
  <button type="button" id="read">Read current DOM</button>
  <button type="button" id="update">Update existing description</button>
  <button type="button" id="duplicate">Add duplicate</button>
  <button type="button" id="remove">Remove description</button>
  <button type="button" id="reset">Reset</button>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      function descriptions() { return $('head meta[name="description"]'); }
      function report() {
        const $description = descriptions(), allValues = [];
        $description.each(function () { allValues.push($(this).attr("content")); });
        const $absent = $('head meta[name="does-not-exist"]');
        $("#result").text([
          "description=" + String($description.attr("content")),
          "description count=" + $description.length,
          "all descriptions=" + JSON.stringify(allValues),
          "og:title=" + $('head meta[property="og:title"]').attr("content"),
          "empty=" + JSON.stringify($('head meta[name="demo-empty"]').attr("content")),
          "missing content=" + String($('head meta[name="demo-no-content"]').attr("content")),
          "absent count=" + $absent.length + "; content=" + String($absent.attr("content")),
          "charset=" + $('head meta[charset]').attr("charset")
        ].join("\n"));
      }
      $("#read").on("click", report);
      $("#update").on("click", function () {
        descriptions().attr("content", "Updated <em>summary</em>"); report();
      });
      $("#duplicate").on("click", function () {
        $("<meta>").attr({ name: "description", content: "Second summary" }).appendTo("head");
        $(this).prop("disabled", true); report();
      });
      $("#remove").on("click", function () { descriptions().remove(); report(); });
      $("#reset").on("click", function () {
        descriptions().remove();
        $("<meta>").attr({ name: "description", content: "Original page summary" }).appendTo("head");
        $("#duplicate").prop("disabled", false); report();
      });
      report();
    });
  </script>
</body>
</html>

Initial output: content="" is an empty string. A missing content attribute or missing element gives undefined; length separately identifies element existence.

description=Original page summary
description count=1
all descriptions=["Original page summary"]
og:title=Meta demo
empty=""
missing content=undefined
absent count=0; content=undefined
charset=utf-8
  1. Read current DOM rereads the document. Initially description is Original page summary and count=1.
  2. Add duplicate makes two descriptions. The getter still reads Original page summary; the full array is ["Original page summary","Second summary"].
  3. Update existing description changes every matching description to Updated <em>summary</em>. Output uses .text(), so it creates no em element.
  4. Remove description gives count=0, description=undefined and all descriptions=[]. Updating now does not create a missing tag.
  5. Reset restores one original description, leaving charset, viewport, og:title and other metadata intact.

Empty, absent and duplicate values

A simple if(value) conflates empty strings and undefined. Check $meta.length for an element, value === undefined for a missing attribute, and value === "" for an intentional empty value. Do not store the literal string "undefined"; String() here only makes diagnostics visible.

The .attr("content") getter reads only the first match. It neither merges duplicates nor finds the newest description. This example uses .each() to collect every value and show count and order. Trace duplicates to templates or SEO settings instead of considering the first readable value proof of correctness.

The setter .attr("content", value) changes all matches. The Update button is only a demonstration that reads follow the current DOM. Omit the second argument when reading. On a real site, do not arbitrarily overwrite metadata managed by a theme or SEO plugin.

Whitespace remains part of a string. Decide its meaning before normalizing it. Display retrieved strings with .text() rather than interpreting them as HTML elsewhere.

Current DOM versus server source

The code reads the running document’s DOM, Document Object Model. After another script changes content, it reads that change; the original server response does not change. In an app that adds metadata asynchronously, read after that operation or refresh at its update point. DOM readiness does not mean every asynchronous operation has finished.

Compare head in developer tools’ Elements with View Source to diagnose differences. Reading or changing a value does not prove a search result or social preview has updated. Google’s JavaScript SEO documentation distinguishes crawling, rendering and indexing; verify actual collection with the relevant service’s tools.

A current-document selector makes no request to another URL. Inspecting another page requires a separate permitted method of retrieving its HTML. This example does not grant access to arbitrary sites’ metadata.