JG.
InicioSobre MíServiciosPortafolioCasosBlogContactoHablemos

Cómo lancé la versión en portugués de una web en inglés y español con hreflang bien hecho

7 min de lectura

Lo que hice el 6 de octubre de 2026 en basher.agency para sumar el portugués a una web que ya posicionaba en inglés y español, con las etiquetas copiadas en vivo y los errores que ya nos habían pasado.

Resumen

Para sumar una versión en portugués a una web que ya existe en inglés y español, cada página nueva tiene que entrar en un grupo hreflang donde todas las versiones se citan entre sí, también las viejas. Si solo pones las etiquetas en la página nueva, Google ve un par sin vuelta y lo ignora. En basher.agency abrimos /pt/ el 6 de octubre de 2026 con una sola versión en portugués que se declara a la vez como pt, pt-BR y pt-PT, con x-default apuntando a la versión en inglés de cada página. El cambio clave fue un paso en el build que arma los grupos completos de forma automática.

De dónde partíamos

Basher es una agencia de marketing iGaming para operadores licenciados. Su web es una app de React con un prerender que genera el HTML de cada ruta con su head SEO. Antes de tocar nada pasé una auditoría técnica y salió 99/A, así que el riesgo no estaba en arreglar cosas rotas sino en romper algo que funcionaba.

La petición fue directa: que cada idioma de la web posicione en su país. Al revisar, solo inglés y español tenían URLs propias. Había textos de interfaz en ruso y ucraniano, sin páginas, y no los abrimos.

Saqué de Search Console las impresiones por país del dominio entre el 7 de julio y el 4 de octubre de 2026, solo del host principal. Fueron 32.320 impresiones repartidas en 183 países. Brasil aportó 383 y Portugal 159. Lo revelador fue ver qué buscaban los brasileños: «basher» (241 impresiones) y «basher agency» (37). En portugués apareció una sola consulta, «b2b em igaming», con una impresión. Había gente buscando la marca desde Brasil y ninguna página en su idioma.

Gráfica de barras de impresiones de basher.agency por país en Search Console entre julio y octubre de 2026, con Brasil y Portugal resaltados
Impresiones por país en Search Console, 7-jul a 4-oct-2026, antes de abrir /pt/. Brasil y Portugal en ámbar.

El mapa de URLs: una página portuguesa por cada par que ya existía

No traduje la web entera. Elegí las páginas con intención clara y les busqué su gemela en los otros idiomas. La primera tanda fueron cinco URLs:

PortuguésInglésEspañol
/pt///es/
/pt/seo-para-cassinos//services/casino-seo//es/seo-para-casinos/
/pt/mercados/brasil//markets/brazil/no existe
/pt/blog//articles//es/blog/
/pt/blog/melhores-cassinos-online-brasil//best-online-casinos//es/mejores-casinos-online/

Diez minutos después de publicar esa tanda salió la segunda: /pt/mercados/portugal/ (gemela de /markets/portugal/) y un post sobre cómo apostar en casino online, que en Brasil hoy se responde con «está prohibido» por la Medida Provisória 1.394 de septiembre de 2026 y en Portugal con las reglas del regulador.

La carpeta lleva el idioma, no el país: /pt/ y no /br/, porque una sola versión sirve a los dos mercados.

Captura de la portada en portugués de basher.agency con el titular Marketing iGaming para operadores licenciados
basher.agency/pt/ en vivo, capturada el 7-oct-2026.

Las etiquetas tal como salen en vivo

Esto es lo que imprime hoy el head de https://basher.agency/pt/, copiado con curl:

<link rel="canonical" href="https://basher.agency/pt/" />
<link rel="alternate" hreflang="pt" href="https://basher.agency/pt/" />
<link rel="alternate" hreflang="pt-BR" href="https://basher.agency/pt/" />
<link rel="alternate" hreflang="pt-PT" href="https://basher.agency/pt/" />
<link rel="alternate" hreflang="en" href="https://basher.agency/" />
<link rel="alternate" hreflang="es" href="https://basher.agency/es/" />
<link rel="alternate" hreflang="x-default" href="https://basher.agency/" />

La home en inglés y la española imprimen el mismo juego, cada una con su canonical propio.

Lo de los tres códigos portugueses hacia la misma URL tiene su historia. El texto está escrito en portugués de Brasil y el html lang dice pt-BR. En la primera tanda declaré solo pt, que ya cubre a cualquier hablante de portugués. Luego el encargo se precisó a «Brasil y Portugal» y sumé pt-BR y pt-PT explícitos. Google acepta varios códigos hacia una URL y así queda escrito para qué mercados es.

Diagrama de un grupo hreflang con las versiones en inglés, español y portugués de basher.agency enlazadas en ambas direcciones
Un grupo hreflang completo: cada versión cita a las otras dos y a sí misma.

Cómo lo resolví en el código

Las páginas en portugués viven en markdown, en una carpeta propia, y cada una declara su pareja en el frontmatter:

path: /pt/
en_path: /
es_path: /es/

La página nueva sabe quiénes son sus hermanas, pero la home en inglés no sabe que existe /pt/. Con dos idiomas esto se arreglaba a mano, par por par. Con tres, si te olvidas de una sola vuelta tienes un «missing return tag», y con decenas de páginas te vas a olvidar.

Así que agregué un paso al prerender que llamé «grupos hreflang completos». Recorre todas las rutas, junta en un mismo grupo las que estén enlazadas por una declaración de idioma en cualquier dirección (es un union-find, nada exótico) y reescribe las alternativas de cada ruta para que declare a todas las demás del grupo con su idioma real. Basta con que la página portuguesa diga «mi par en inglés es /» para que la home en inglés y la española la incluyan solas.

Le puse un freno a propósito: si dos rutas de un mismo grupo comparten idioma, el paso no toca ese grupo. Prefiero dejar la declaración original antes que inventar una alternativa equivocada.

Antes de publicar comparé el build nuevo contra el de la rama principal, URL por URL. Resultado: 0 cambios en las 264 URLs que ya existían, salvo el portugués añadido en 9 de ellas. Sin esa comparación no toco el head de un sitio que ya posiciona.

x-default y sitemap

El x-default apunta a la versión en inglés de cada página, no a la home global. Esto lo aprendí a golpes. En julio, el script ponía el x-default de todas las páginas apuntando a la portada. La portada no devolvía esas páginas, y una auditoría de Ahrefs marcó 85 errores de hreflang sin recíproco. El arreglo fue una línea: si la ruta tiene par en inglés, el x-default va a ese par; si no, a sí misma. Las páginas en portugués heredaron esa lógica sin tocar nada.

En el sitemap las cinco primeras URLs /pt/ entraron en el sitemap de páginas y los posts en el de artículos, dentro de un índice que declara el robots.txt. Lo que no hay son bloques xhtml:link en el XML. Google acepta el hreflang en el head HTML, en cabeceras HTTP o en el sitemap, y con uno de los tres basta. No mezcles dos métodos mantenidos por separado: acaban contradiciéndose.

Errores típicos (varios nos pasaron)

Etiquetas solo en la página nuevaLa versión vieja no devuelve el enlace y Google descarta el par. Se arregla generando los grupos desde el build, no a mano.
x-default a la portadaNos dejó 85 recíprocos rotos en julio. El x-default tiene que ser la versión por defecto de esa misma página.
Canonical a otro idiomaSi /pt/ hace canonical a /, le estás diciendo a Google que no indexe el portugués. Cada versión, canonical a sí misma.

Otro que vi en esta cartera: perder el hreflang en un rediseño. En bcontent.mx, al revertir un rediseño, se fue sin avisar el hreflang corregido junto con otras mejoras SEO y hubo que rescatarlas en otro commit. Desde entonces, antes de cualquier revert reviso canonical, hreflang, schema y sitemap.

Y uno de despliegue: el push a producción no siempre se publica al momento. Ese día el proceso automático no recogió el cambio y tuve que lanzar la publicación a mano. Comprueba con curl la URL en vivo antes de darlo por publicado.

Indexación y lo que falta medir

La primera tanda salió el 6 de octubre a las 21:35 (hora de Lima) y la segunda a las 21:45. Con la primera mandé 14 URLs nuevas y cambiadas por IndexNow (respuesta 200), reenvié los sitemaps en Search Console y, por la noche, las 268 URLs del sitio por IndexNow y las primeras 100 por la API de envío de Bing, que es su cuota diaria. La Indexing API de Google respondió 429 por cuota agotada al primer envío, así que esa parte queda para los días siguientes.

Lo que todavía no puedo contarte es el resultado. Search Console tiene datos hasta el 4 de octubre y las páginas en portugués existen desde el 6. Lo honesto es medir Brasil y Portugal en 28 días contra la línea base de la gráfica de arriba: 383 y 159 impresiones en 90 días. Si quieres ver cómo trabajo este tipo de proyectos, está en mi página de servicios de SEO, y si tu web está en plena migración de estructura te sirve leer cómo migrar una web sin perder SEO. Para el resto del head técnico tengo la guía de SEO técnico.

Preguntas frecuentes

¿Necesito una versión distinta para Brasil y otra para Portugal?

No, si el contenido es el mismo. Puedes tener una sola página en portugués y declararla con pt, pt-BR y pt-PT apuntando a la misma URL. Separa versiones solo cuando el texto cambie de verdad por país, por ejemplo por leyes, precios o vocabulario.

¿Dónde debe apuntar el x-default?

A la versión por defecto de esa misma página, normalmente la inglesa. Si apuntas el x-default de todas las páginas a la portada, la portada no las devuelve y aparecen errores de recíproco. En basher.agency eso nos dejó 85 errores antes de corregirlo.

¿Tengo que poner hreflang en el sitemap y en el HTML?

No. Google acepta el head HTML, las cabeceras HTTP o el sitemap, y con un método basta. En basher.agency va en el head de cada página, generado en el build. Mezclar dos métodos mantenidos por separado es la forma más rápida de que se contradigan.

¿Qué pasa si una página no tiene versión en algún idioma?

Simplemente no la declaras. /pt/mercados/brasil/ tiene par en inglés pero no en español, así que su grupo tiene dos versiones. Nunca apuntes a una página parecida para rellenar el hueco.