166

If I put a div in the head and display:none, than use JavaScript to display it, will this work?

Edit:

I have stuff loaded in AJAX. And as my AJAX changes the "main" portion of the site, I want to change the meta-tags as well.

Brett DeWoody
  • 59,771
  • 29
  • 135
  • 184
TIMEX
  • 259,804
  • 351
  • 777
  • 1,080
  • 51
    that's like wearing a shoe as a hat – Ben Apr 02 '10 at 19:38
  • Why do you want to change the meta-tags? – Mikael Svenson Apr 02 '10 at 19:41
  • 9
    or using a text editor as an ide. No wait, that's considered cool. – Dan Rosenstark Apr 02 '10 at 19:45
  • 23
    You're right I"m stupid – TIMEX Apr 02 '10 at 19:59
  • 2
    Hi TIMEX, maybe a change of the accepted answer is in its place? If no other reason but to give Byron a break on the downvotes for his outdated answer. – Alex Feb 23 '16 at 17:49
  • I'm seeing why I want to do it. I have a features.php page with 20 show/hide divs controlled from a navbar selector. I think google doesn't like 80% of my content on one page with one title and description, the general 'features'. I suspect having 20 titles is going to better than having one 'Features', but that could become disorderly. I guess there are two solutions: (a) make 20 pages instead of divs, or (b) post to the features page to determine what the title and content should be. I think google has some kind of setting that accounts for this, but sounds like it could be complicated. – gunslingor Mar 02 '16 at 00:53
  • 1
    I want to do this so I can manage the meta tags (og in particular) with my javascript framework, then have my prerender engine write/cache this for crawlers. Otherwise I'd need additional middleware to determine the tags from my API before rendering my SPA's index, which would slow down loading, for one thing... – Soft Bullets Mar 20 '17 at 13:19
  • 1
    @SoftBullets I stumbled onto this because I am using a library that relies on meta tags to configure it, but the content needs to be changed based on an external file. I am fairly certain even with a shoe for a hat, we will be the ones looking less stupid. – Abandoned Cart Jun 06 '19 at 16:27
  • I'm writing a website framework that has an always-resident piece then reads in the individual pages into a div. I need search engines to set the meta information for the current page in the resident piece. I think using JavaScript might work, so I'm interested in the answers. – David Spector Mar 24 '20 at 20:53

20 Answers20

249

Yes, it is.

E.g. to set the meta-description:

document.querySelector('meta[name="description"]').setAttribute("content", _desc);
jayms
  • 3,828
  • 2
  • 11
  • 18
  • 46
    Glad someone gave an answer in pure js (as requested in the question)! – Soft Bullets Mar 20 '17 at 13:13
  • Hi jayms. Thanks for the tip. But I tried this method to try to change og:title tag, but didn´t work. Here´s how I did it: document.querySelector('meta[name="og:title"]').setAttribute("content", "Example with title meta tag"); Any ideas? – Jorge Mauricio Jun 11 '20 at 19:47
  • 8
    It seems you would need to query for the `property` attribute, not the `name` attribute, i.e. `meta[property="og:title"]` – jayms Jun 13 '20 at 12:23
162

Yes, you can do that.

There are some interesting use cases: Some browsers and plugins parse meta elements and change their behavior for different values.

Examples

Skype: Switch off phone number parser

<meta name="SKYPE_TOOLBAR" content="SKYPE_TOOLBAR_PARSER_COMPATIBLE">

iPhone: Switch off phone number parser

<meta name="format-detection" content="telephone=no">

Google Chrome Frame

<meta http-equiv="X-UA-Compatible" content="chrome=1">

Viewport definition for mobile devices

<meta name="viewport" content="width=device-width, initial-scale=1.0">

This one can be changed by JavaScript. See: A fix for iPhone viewport scale bug

Meta description

Some user agents (Opera for example) use the description for bookmarks. You can add personalized content here. Example:

<!DOCTYPE html>
<title>Test</title>
<meta name="description" content="this is old">
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>

<button>Change description</button>

<script type='text/javascript'>
$('button').on('click', function() {
    // Just replacing the value of the 'content' attribute will not work.
    $('meta[name=description]').remove();
    $('head').append( '<meta name="description" content="this is new">' );
});
</script>

So, it’s not just about search engines.

fuxia
  • 62,923
  • 6
  • 54
  • 62
  • 10
    I suspect most metas like this have effects that aren't changeable after the page is loaded. But yes, meta is far more than just `keywords` and `description`. – bobince Apr 02 '10 at 22:27
  • also you can use meta tags for mobile browsers like ios you may want to modify values for landscape. – siniradam Nov 13 '11 at 19:37
  • 2
    @bobince: Actually, the SKYPE_TOOLBAR one still takes effect if you insert it with js (which is useful as html5 validator doesn't like that meta tag). – DaedalusFall Nov 15 '11 at 13:23
  • 1
    @DaedalusFall: yeah, I think you can only do that with `document.write` in the header though, it's too late to change it once the page is loaded as Skype will have already mangled the DOM, horrible thing! – bobince Nov 15 '11 at 14:17
  • 1
    This is very useful with social sharing to services like Facebook. For example, to change the og:title element: `$('meta[property="og:title"]').replaceWith('');` – bdanin Aug 14 '14 at 13:05
  • However, it appears that Facebook is scraping the URL prior to javascript running, so client-side replacements like this don't appear to actually work for social sharing applications. – bdanin Aug 14 '14 at 15:32
  • 3
    You can do some cool stuff with this. I change the Chrome address bar color when the a slide in the header changes. `const meta = document.querySelector('meta[name=theme-color]'); meta.setAttribute("content", colors[slideIndex]);` Chrome on Android detects the update and changes the color – Dominic Dec 20 '18 at 10:00
  • What is the code if I'm not using jQuery (because it's bloated and because I don't want to change the meaning of HTML by using CSS descriptors)? – David Spector Mar 24 '20 at 20:56
73

You'd use something like (with jQuery):

$('meta[name=author]').attr('content', 'New Author Name');

But that would be mostly pointless as meta tags are usually only scraped when the document is loaded, usually without executing any JavaScript.

MiffTheFox
  • 21,302
  • 14
  • 69
  • 94
  • 7
    It even works with selectors such as `$('meta[property=og:somestuff]')`, which I suspected it would clash with the jQuery selection syntax because of the colon. – pau.moreno Dec 29 '11 at 17:18
  • 8
    In case anyone else is looking for this exact solution, you need to put quotes around the og:somestuff - I needed the content of the image tag, this was my code: var imgurl = $("meta[property='og:image']").attr("content"); – Daniel Feb 13 '12 at 05:47
  • 2
    Confirmed that it works for meta viewport setting (needed this to enable / disable zoom for certain subpages on jQuery Mobile). Thanks! – NPC May 10 '12 at 13:05
  • 1
    @stealthcopter I can verify that this doesn't :( wait, it does, but the changes are not visible in FFox's "view source" window..? – yPhil May 13 '15 at 21:26
  • 1
    @yPhil This is javascript (or jQuery) so any and all changes that you make to the DOM are not reflected when viewing the source code from the browser. It will reflect when you use the Developer's Tool to view source. The browser source is loaded only once when the page loads.. ajax request requests are not page loads. – Zubair1 Sep 13 '17 at 12:40
  • I wanted to change the externally-viewed Description and Keywords depending on what HTML is loaded using Ajax, to cross-fade pages. Clearly, that won't work. – David Spector Jan 06 '20 at 17:02
  • For cross-fading, the proper solution is to add a user-visible cross-fade page transition to the browsers, IMO. – David Spector Jan 06 '20 at 17:04
  • "meta tags are usually only scraped when the document is loaded" If this is true, my whole scheme for cross-fading pages by loading via JavaScript will fail for SEO. I hope it isn't true. – David Spector Mar 24 '20 at 21:00
55

It is definitely possible to use Javascript to change the meta tags of the page. Here is a Javascript only approach:

document.getElementsByTagName('meta')["keywords"].content = "My new page keywords!!";
document.getElementsByTagName('meta')["description"].content = "My new page description!!";
document.title = "My new Document Title!!";

I have verified that Google does index these client side changes for the code above.

Tim
  • 1,105
  • 13
  • 14
  • 4
    Interesting! Thanks for making me aware of the `element = collection[name]` syntax. – jayms Jun 09 '19 at 16:03
  • Make sure the meta tags for keywords and description exist along with the title and the above will work. https://codepen.io/tmoses/pen/RwaZOXo (see the console.log outputs) – Tim Sep 01 '20 at 15:36
  • I tested the above code, surrounded by script tags in the head as well as near the footer (obviously I know) but it is not working for me. I know I am the problem but am stumped. – user1469 Feb 12 '21 at 15:17
  • user1469 Mimic your setup in codepen/similar and send a link. – Tim Feb 12 '21 at 15:58
33

You can change meta with, for example, jQuery calls, like this ones:

$('meta[name=keywords]').attr('content', new_keywords);
$('meta[name=description]').attr('content', new_description);

I think it does matter for now, since google said that they will index ajax content via #!hashes and _escaped_fragment_ calls. And now they can verify it (even automatically, with headless browsers, see the 'Creating HTML Snapshots' link on the page mentioned above), so I think it is the way for hardcore SEO guys.

wkw
  • 3,865
  • 3
  • 25
  • 24
eyedmax
  • 383
  • 3
  • 5
  • 3
    Thank you for this. Just solved my problem. As facebook has open graph. The site I'm developing has a History jQuery plugin and hash tags. So the FB open graph url and description need to be changed when ever a hash change is present. +1 for a great answer and not being negative towards a fair question. – Damien Keitel Feb 11 '12 at 09:30
  • 5
    Actually, now google is able to run javascript, too with no need to create page snapshots, so now dynamic metatags do matter a lot! – Francesco Abbruzzese Jun 24 '14 at 13:35
16

You can use more simpler and lighter solution:

document.head.querySelector('meta[name="description"]').content = _desc
Ali Seyfollahi
  • 2,662
  • 2
  • 21
  • 29
13

meta-tags are part of the dom and can be accessed and -i guess- changed, but search-engines (the main consumers of meta-tags) won't see the change as the javascript won't be executed. so unless you're changing a meta-tag (refresh comes to mind) which has implications in the browser, this might be of little use?

futtta
  • 5,917
  • 2
  • 21
  • 33
  • 3
    +1 - I landed on this question because I was wondering specifically about meta refresh. I am creating an app which uses ajax polling to refresh the data on screen and I want to provide a crude fallback for browsers that do not have javascript enabled. I am thinking that I could accomplish this by creating a meta refresh tag by default and if javascript is enabled, just remove the meta tag. - Now to see if it actually works... – jessegavin May 15 '11 at 04:43
  • 1
    @futtta, the meta description tag is used for bookmark descriptions in Opera, so there is actually a benefit to the user that your meta description can be changed. – XP1 Aug 15 '11 at 12:12
11
$(document).ready(function() {
  $('meta[property="og:title"]').remove();
  $('meta[property="og:description"]').remove();
  $('meta[property="og:url"]').remove();
  $("head").append('<meta property="og:title" content="blubb1">');
  $("head").append('<meta property="og:description" content="blubb2">');
  $("head").append('<meta property="og:url" content="blubb3">');
});
user3320390
  • 119
  • 1
  • 2
  • 6
    I started out with your example but realized that you don't have to remove and re-add the meta-tags. You can just change the content-attribute like this: `jQuery('meta[property="og:title"]').attr('content', "blubb1");` – Tobias Beuving Feb 24 '15 at 16:53
  • You're correct @user3320390. It's different removing a tag than changing it. FB acts for what is HTML written and NOT for the values of the tags. – Pedro Ferreira May 11 '16 at 17:18
11

It should be possible like this (or use jQuery like $('meta[name=author]').attr("content");):

<html>
<head>
<title>Meta Data</title>
<meta name="Author" content="Martin Webb">
<meta name="Author" content="A.N. Other">
<meta name="Description" content="A sample html file for extracting meta data">
<meta name="Keywords" content="JavaScript, DOM, W3C">

</head>

<body>
<script language="JavaScript"><!--
if (document.getElementsByName) {
  var metaArray = document.getElementsByName('Author');
  for (var i=0; i<metaArray.length; i++) {
    document.write(metaArray[i].content + '<br>');
  }

  var metaArray = document.getElementsByName('Description');
  for (var i=0; i<metaArray.length; i++) {
    document.write(metaArray[i].content + '<br>');
  }

  var metaArray = document.getElementsByName('Keywords');
  for (var i=0; i<metaArray.length; i++) {
    document.write(metaArray[i].content + '<br>');
  }
}
//--></script>
</body>

</html>
Mikael Svenson
  • 39,181
  • 7
  • 73
  • 79
6

The name attribute allows you to refer to an element by its name (like id) through a list of children, so fast way is:

document.head.children.namedItem('description').content = '...'

— or even just:

document.head.children.description.content = '...'

But if you are not sure if such a meta-tag exists, then it is better to add a check like this:

let metaDescription = document.head.children.description
if (metaDescription == null) {
  metaDescription = document.createElement('meta')
  metaDescription.name = 'description'
  document.head.append(metaDescription)
}
metaDescription.content = '...'
Yozhik
  • 61
  • 1
  • 5
5
var metaTag = document.getElementsByTagName('meta');
for (var i=0; i < metaTag.length; i++) {
    if (metaTag[i].getAttribute("http-equiv")=='refresh')
        metaTag[i].content = '666';
    if (metaTag[i].getAttribute("name")=='Keywords')
        metaTag[i].content = 'js, solver';
}
manlio
  • 18,345
  • 14
  • 76
  • 126
LanPartacz
  • 51
  • 1
  • 1
5

For anyone trying to change og:title meta tags (or any other). I managed to do it this way:

document.querySelector('meta[property="og:title"]').setAttribute("content", "Example with og title meta tag");

Attention that the 'meta[property="og:title"]' contains the word PROPERTY, and not NAME.

Jorge Mauricio
  • 411
  • 6
  • 18
2

simple add and div atribute to each meta tag example

<meta id="mtlink" name="url" content="">
<meta id="mtdesc" name="description" content="" />
<meta id="mtkwrds" name="keywords" content="" />

now like normal div change for ex. n click

<a href="#" onClick="changeTags(); return false;">Change Meta Tags</a>

function change tags with jQuery

function changeTags(){
   $("#mtlink").attr("content","http://albup.com");
   $("#mtdesc").attr("content","music all the time");
   $("#mtkwrds").attr("content","mp3, download music, ");

}
Burhan Ibrahimi
  • 367
  • 3
  • 14
2

If we don't have the meta tag at all, then we can use the following:

var _desc = 'Out description';
var meta = document.createElement('meta');
meta.setAttribute('name', 'description');
meta.setAttribute('content', _desc);
document.getElementsByTagName('head')[0].appendChild(meta);
Roman
  • 19,236
  • 15
  • 93
  • 97
1

No, a div is a body element, not a head element

EDIT: Then the only thing SEs are going to get is the base HTML, not the ajax modified one.

Ben
  • 16,275
  • 9
  • 45
  • 63
1

Yes, it is possible to add metatags with Javascript. I did in my example

Android not respecting metatag removal?

But, I dont know how to change it other then removing it. Btw, in my example.. when you click the 'ADD' button it adds the tag and the viewport changes respectively but I dont know how to revert it back (remove it, in Android).. I wish there was firebug for Android so I saw what was happening. Firefox does remove the tag. if anybody has any ideas on this please note so in my question.

Community
  • 1
  • 1
Chamilyan
  • 9,347
  • 10
  • 38
  • 67
1
var description=document.getElementsByTagName('h4')[0].innerHTML;
var link = document.createElement('meta');
  
link.setAttribute('name', 'description');
  
link.content = description;
  
document.getElementsByTagName('head')[0].appendChild(link);
var htwo=document.getElementsByTagName('h2');
var hthree=document.getElementsByTagName('h3');
var ls=[];
for(var i=0;i<hthree.length;i++){ls.push(htwo[i].innerHTML);}

for(var i=0;i<hthree.length;i++){ls.push(hthree[i].innerHTML);}

var keyword=ls.toString()
;
var keyw = document.createElement('meta');
  
keyw.setAttribute('name', 'keywords');
  
keyw.content = keyword;
  
document.getElementsByTagName('head')[0].appendChild(keyw);

in my case, I write this code and all my meta tags are working perfectly but we can not see the actual meta tag it will be hidden somewhere.

Somen Das
  • 366
  • 2
  • 7
0

have this in index

<link rel="opengraph" href="{http://yourPage.com/subdomain.php}"/>

have this in ajaxfiles og:type"og:title"og:description and og: image

and add this also

<link rel="origin" href={http://yourPage.com}/>

then add in js after the ajaxCall

FB.XFBML.parse();

Edit: You can then display the correct title and image to facebook in txt/php douments(mine are just named .php as extensions, but are more txt files). I then have the meta tags in these files, and the link back to index in every document, also a meta link in the index file for every subfile..

if anyone knows a better way of doing this I would appreciate any additions :)

sunto
  • 87
  • 1
  • 1
  • 10
  • This does not seem to be an answer to the question about how to dynamically add meta-tags? – Alex Feb 23 '16 at 18:13
0

This seems to be working for a little rigidly geometrically set app where it needs to run on both mobile and other browsers with little change, so finding the mobile/non-mobile browser status and for mobiles setting the viewport to device-width is needed. As scripts can be run from the header, the below js in header seems to change the metatag for device-width Before the page loads. One might note that the use of navigator.userAgent is stipulated as experimental. The script must follow the metatag entry to be changed, so one must choose some initial content, and then change on some condition.

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>  
  var userAgentHeader = navigator.userAgent ; 
  var browserIsMobileOrNot = "mobileNOT" ; 
  if( userAgentHeader.includes( "Mobi" ) ) { 
    browserIsMobileOrNot = "mobileYES" ; 
    //document.querySelector('meta[name="viewport"]').setAttribute( "content", "width=device-width, initial-scale=1.0" );
  } else { 
    browserIsMobileOrNot = "mobileNOT" ;  
    document.querySelector('meta[name="viewport"]').setAttribute( "content", "");
  }
</script>

<link rel="stylesheet" href="css/index.css">

. . . . . .

0

Here is how to do it with plain javascript. I used it to change the header color in the new Safari 15 beta:

<html><head>

    <meta id="themeColor" name="theme-color" content="">

</head><body><script>

    var delay = 50;
    var increment = 5;
    var current = 0 - increment;

    function setHeaderColor(){

        current += increment;
        if (current > 360) current = 0;

        var colorStr = 'hsl('+current+',100%,50%)';
        themeColor.content = colorStr;
        textBlock.style.color = colorStr;
    }

    setInterval(setHeaderColor, delay);

</script><pre id="textBlock" style="font-size:30px;">

  Needs Safari 15

</pre></body></html>

Link to working example: blog.svija.love.

Andy Swift
  • 2,179
  • 3
  • 32
  • 53