Metaetiquetas

Metas y JSON en Frameworks de JS

Diferentes formas de poner metaetiquetas y datos estructurados en una web de Javascript

Metas y JSON en Frameworks de JS
Autor
Carlos Sánchez
Temática
Metaetiquetas Tecnologías
Publicado
2022-07-01
Revisado
2026-10-30

Los distintos Frameworks de Javascript tienen sus peculiaridades. Una de ellas es que las metaetiquetas y los datos estructurados no se meten de una forma tan sencilla como en otro tipo de webs.

Aquí expongo unas formas sencillas pero eficaces de añadirlas en los Frameworks/librerías más conocidas de JS (que funcionan para sus descendientes).

Hay que entender que donde pone React, también vale la implementación en sus sucedáneos, aunque Next y Gatsby tienen su propia forma de hacerlo y la explico aparte, y donde pone Vue también afecta a su sucedáneo Nuxt, que funciona igual.

Actualización 30/10/2026: He actualizado el artículo entero. Cuando lo escribí, React y Vue necesitaban librerías como react-helmet o vue-helmet, que llevan años sin mantenerse, y hoy React, Next, Nuxt y Angular ya traen su propia forma de hacerlo, así que los ejemplos son con eso. Lo he revisado con la documentación de las versiones actuales: React 19, Next.js 16, Nuxt 4 (Vue 3) y Angular 22.

Meta etiquetas

React

Para añadir meta etiquetas en React, antes había que instalar el paquete de react-helmet, que no se actualiza desde 2020. Desde React 19 ya no hace falta: simplemente debemos añadir en el componente las metaetiquetas que queramos usar y React las coloca en el <head>, estén donde estén:
function App() {
return (
<div className="App">
<title>App Title</title>
<meta name="description" content="App Description" />
<meta name="theme-color" content="#008f68" />
</div>
);
}
export default App;

Ojo con el title: tiene que llevar un único texto, así que si es dinámico hay que montarlo como {`Resultados página ${pagina}`} y no como Resultados página {pagina}, que da error.

Next.js

En Next.js (con el App Router) se usa su propia Metadata API: se exporta un objeto metadata desde el page.js o el layout.js y Next genera las etiquetas en el <head>. El theme-color va aparte, en el export viewport:
export const metadata = {
title: 'App Title',
description: 'App Description',
alternates: {
canonical: 'https://mysite.com/example',
},
};
export const viewport = {
themeColor: '#008f68',
};
export default function Page() {
return <h1>Inicio</h1>;
}

Si las metas dependen de datos (por ejemplo, de la ficha de un producto), en lugar del objeto se exporta una función generateMetadata que devuelve lo mismo. En Gatsby pasa algo parecido: tiene su Head API, que consiste en exportar un componente Head desde la página y que sustituye a react-helmet.

Vue y Nuxt

En Vue, el código para las meta etiquetas era por medio de vue-helmet, que está abandonado. Ahora lo estándar es Unhead, que es lo que usa Nuxt por dentro, con useSeoMeta para las metas y useHead para el resto de etiquetas:
<script setup>
// En Nuxt no hace falta este import
import { useHead, useSeoMeta } from '@unhead/vue';
useSeoMeta({
title: 'My Title',
description: 'My Description',
});
useHead({
link: [{ rel: 'canonical', href: 'https://mysite.com/example' }],
});
</script>

En Nuxt viene de serie. En Vue sin Nuxt hay que instalar el paquete (npm install @unhead/vue) y registrarlo en el main.js con createHead(), que se importa desde '@unhead/vue/client'.

Angular

En el caso de Angular, antes recomendaba la librería ngx-seo, que se quedó en Angular 16, pero no hace falta ninguna: Angular trae de serie los servicios Title y Meta, que se incluyen en la página por medio de este código:
import { Component, inject } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
@Component({
selector: 'app-home',
template: '<h1>Pagina de Inicio</h1>'
})
export class HomeComponent {
private title = inject(Title);
private meta = inject(Meta);
constructor() {
this.title.setTitle('Home Page | Replay Value');
this.meta.updateTag({ name: 'description', content: 'Descripción de la página de inicio' });
// También puedes actualizar otros metadatos SEO según sea necesario
}
}

Para que estas etiquetas lleguen en el HTML y no dependan de que se ejecute el JavaScript, hay que tener el renderizado en servidor activado con @angular/ssr. El título también se puede poner directamente en las rutas, con la propiedad title.

Datos Estructurados

La mejor forma de explicar cómo realizar algo en programación es con ejemplos, así que haré los ejemplos con un Json de Organization en cada una de las ramas. Por cuestión de optimización, recomiendo siempre que vayan en el footer.

Datos estructurados en React

Para este propósito ya no hace falta React Helmet: el JSON-LD se pone con una etiqueta script normal dentro del componente. A diferencia del title y las metas, React no la mueve al <head>, se queda donde la pongas, así que la puedes dejar en el footer. Es lo mismo que recomienda la documentación de Next.js, que además aconseja cambiar el carácter < por \u003c para evitar que se pueda inyectar código.

JSON de Organization en React

const jsonLd = {
'@context': 'https://schema.org',
'@type':'Organization',
url:'https://google.com',
name:'Google',
contactPoint: {
'@type':'ContactPoint',
telephone:'01293019413',
contactType:'Customer service'
}
};
function Footer() {
return (
<footer>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
/>
</footer>
);
}

Datos estructurados con Vue

Para este caso, recomendaría utilizar el mismo useHead de Unhead (vue-jsonld también está abandonado) por su sencillez y su compatibilidad con Server Side Rendering. Con tagPosition: 'bodyClose' el script va al final del body, y si en innerHTML se le pasa el objeto tal cual, Unhead lo convierte a JSON y escapa el carácter < por su cuenta.

JSON-LD de Organization en Vue y Nuxt

<script setup>
// En Nuxt no hace falta este import
import { useHead } from '@unhead/vue';
useHead({
script: [
{
type: 'application/ld+json',
tagPosition: 'bodyClose',
innerHTML: {
'@context': 'https://schema.org',
'@type':'Organization',
url:'https://google.com',
name:'Google',
contactPoint: {
'@type':'ContactPoint',
telephone:'01293019413',
contactType:'Customer service'
}
}
}
]
});
</script>

Singleton para Angular

Para añadir JSON-LD en Angular, es conveniente utilizar un servicio Singleton (con providedIn: 'root'), se puede utilizar AppComponent, pero nos supondría ciertos problemas de optimización.

Para la inserción dinámica y más información debido a lo problemático que suele ser Angular, recomiendo este artículo.

Ejemplos:

JSON-LD de Organization en Angular

import { Injectable, inject, DOCUMENT } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class JsonLdService {
private doc = inject(DOCUMENT);
setJsonLd(datos: object) {
let script = this.doc.getElementById('json-ld');
if (!script) {
script = this.doc.createElement('script');
script.id = 'json-ld';
script.setAttribute('type', 'application/ld+json');
this.doc.body.appendChild(script);
}
script.textContent = JSON.stringify(datos).replace(/</g, '\\u003c');
}
}

Y luego, en el componente de la página donde se quiera:
import { Component, inject } from '@angular/core';
import { JsonLdService } from './json-ld.service';
@Component({
selector: 'app-home',
template: '<h1>Pagina de Inicio</h1>'
})
export class HomeComponent {
constructor() {
inject(JsonLdService).setJsonLd({
'@context': 'https://schema.org',
'@type':'Organization',
url:'https://google.com',
name:'Google',
contactPoint: {
'@type':'ContactPoint',
telephone:'01293019413',
contactType:'Customer service'
}
});
}
}

Con @angular/ssr el script ya sale en el HTML que genera el servidor, y al estar en un servicio con providedIn: 'root' hay una sola instancia para toda la aplicación, que reutiliza la misma etiqueta al cambiar de página.
Recomiendo testear los códigos antes de utilizarlos, son simplemente una ejemplificación, lo ideal es hacerlos dinámicos.

Si tienes alguna duda al respecto siempre la puedes consultar en mi canal de Discord o contratarme.

Si te gusta este artículo, me ayudarías un montón compartiendo mi contenido:
Formación
No se te da mal el SEO técnico

Te falta mi máster. Accede a una formación avanzada que te permitirá aplicar e implementar SEO en cualquier tipo de web.

Accede al Máster de SEO Técnico
Tal vez te interesen otros artículos:
Artículos de SEO