Universally Documentation

Step-by-step guides, multilingual SEO tips, and best practices to help you translate and scale your WordPress website.

Astro with language subdomains

In the Subdomain serving mode, Universally serves each language on its own subdomain, such as fr.example.com, by fetching the page from your main domain and translating it. Your Astro app renders only the source language. The integration runs in proxy mode, where it adds the hreflang links and the language switcher to your pages and nothing else.

Before you start

  • The project is in the Subdomain serving mode. Pick Subdomain under How should translated pages be served? when you create it. A JavaScript mode project can move here with Move to language subdomains on its Setup page. Moving a Subdomain project back to the SDK is not available yet.
  • Access to your domain's DNS.
  • The Owner or Admin role to create the project, and Owner, Admin, or Editor to add hostnames and click Re-check now.

Install in proxy mode

  1. Install the package and add UNIVERSALLY_API_KEY to .env, as in Install the Astro integration.
  2. Register the integration with mode: 'proxy':
import universally from '@universally-sdk/astro';
import { defineConfig } from 'astro/config';

export default defineConfig({
  site: 'https://example.com',
  integrations: [universally({ mode: 'proxy' })]
});
  1. Add the head tag once in your layout, inside <head>:
---
import { UniversallyHead } from '@universally-sdk/astro/components';
---

<head>
  <UniversallyHead />
</head>

Setting UNIVERSALLY_MODE=proxy in the environment does the same as the mode option.

Add a language subdomain

The dashboard side is the same for every project type and is covered in full in Language subdomains.

  1. Open All Languages. In the Languages card, click Add subdomain for language.
  2. In Add Target Language, pick Language and Region, then choose the Subdomain format: Region Code, Language Code, or Custom. The segment becomes the subdomain, so French with Language Code on example.com becomes fr.example.com. A leading www is dropped from your domain. The hostname is created for you.
  3. Add the three DNS records shown with their Name and Value, in any order:
Type Name Value Purpose
CNAME fr.example.com proxy.universally.app Routing
TXT shown once Cloudflare issues it shown once Cloudflare issues it Ownership
CNAME _acme-challenge.fr.example.com fr.example.com.afc20bbc0f5b23e9.dcv.cloudflare.com Certificate

Records must not be proxied. On Cloudflare, set Proxy status to DNS only: a proxied record resolves as an A record, which cannot be validated.

  1. Wait for the checks. They run every 5 minutes, and verification and the certificate take a few minutes. Click Re-check now to check straight away.
  2. Restart or rebuild your Astro site once the subdomain shows Live. Hostnames are read when your config runs.

The status pill reads Add DNS records, Verifying, Live, DNS moved, or Failed. The timeline steps through DNS added, Domain verified, SSL issued, and Live. A hostname is active once Cloudflare reports both the hostname and its certificate as active. For language settings in general, see Add languages.

What proxy mode renders

On https://example.com/about, <UniversallyHead /> renders the source and x-default links on your site, and each target at its hostname with the same path:

<link rel="alternate" hreflang="en-us" href="https://example.com/about" />
<link rel="alternate" hreflang="fr" href="https://fr.example.com/about" />
<link rel="alternate" hreflang="x-default" href="https://example.com/about" />

These links have to be in your source HTML, because the proxy never serves your main domain. See hreflang tags. The switcher script follows unless switcher: false is set.

Proxy mode skips everything else:

  • No /fr/ routes. A language path on your own server stays a 404, which is correct.
  • No catalog, reports, or polling. Your server talks to Universally once, when the config runs.
  • /_universally/revalidate answers 404.
  • t() and href() return their argument, so a layout written for SDK mode keeps working.

Verify it worked

  • https://fr.example.com/about loads your page in French.
  • The source of https://example.com/about has a link to https://fr.example.com/about.

If it does not work

  • A language is missing from the links: it has no active hostname yet. The log says "…has no active hostname in Universally, so it was left out of the hreflang links." Finish its DNS records, wait for Live, then rebuild.
  • The records cannot be validated: a record is proxied. On Cloudflare, switch it to DNS only.
  • The links do not change after a subdomain goes live: hostnames are read when the config runs. Restart or rebuild.

More cases are in Astro integration troubleshooting.

Was this helpful?